Beispiel #1
0
// keyResponse translates key board input into two different actions: canceling
// the current prompt and making a choice in the cycle prompt.
// Canceling a prompt corresponds to the "CycleConfig.CancelKey" being pressed.
// Making a choice in the cycle prompt corresponds to releasing all of the
// modifiers used to initiate showing the prompt (when "CycleConfig.AutoChoose"
// is true).
// If CancelKey is empty, then no cancel key functionality is provided.
// If AutoChoose is false, then releasing the modifiers will have no effect.
//
// For thos interested in the X details:
// The prompt cycle dialog needs to choose the selection when the
// modifiers (i.e., "alt" in "alt-tab") are released.
// The only way to do this (generally) is to check the raw KeyRelease event.
// Namely, if the keycode *released* is a modifier, we have to and-out
// that modifier from the key release event data. If the modifiers
// remaining aren't up to snuff with the original grabbed modifiers,
// then we can finally "choose" the selection.
// TL;DR - This is how we "exit" the prompt cycle dialog.
func (cycle *Cycle) keyResponse() xevent.KeyReleaseFun {
	f := func(X *xgbutil.XUtil, ev xevent.KeyReleaseEvent) {
		if !cycle.showing {
			return
		}

		mods, kc := keybind.DeduceKeyInfo(ev.State, ev.Detail)

		// If the key release is the cancel key, quit the prompt and
		// don't do anything.
		if keybind.KeyMatch(X, cycle.config.CancelKey, mods, kc) {
			cycle.Hide()
			return
		}

		mods &= ^keybind.ModGet(X, ev.Detail)
		if cycle.grabMods > 0 {
			if mods&cycle.grabMods == 0 {
				cycle.Choose()
			}
		} else {
			if keybind.KeyMatch(X, cycle.config.ConfirmKey, mods, kc) {
				cycle.Choose()
			}
		}
	}
	return xevent.KeyReleaseFun(f)
}
Beispiel #2
0
func grabKeyboardAndMouse(m *Manager) {
	if m == nil {
		return
	}

	//go func() {
	X, err := xgbutil.NewConn()
	if err != nil {
		logger.Info("Get New Connection Failed:", err)
		return
	}
	keybind.Initialize(X)
	mousebind.Initialize(X)

	err = keybind.GrabKeyboard(X, X.RootWin())
	if err != nil {
		logger.Info("Grab Keyboard Failed:", err)
		return
	}

	grabAllMouseButton(X)

	xevent.ButtonPressFun(
		func(X *xgbutil.XUtil, e xevent.ButtonPressEvent) {
			dbus.Emit(m, "KeyReleaseEvent", "")
			ungrabAllMouseButton(X)
			keybind.UngrabKeyboard(X)
			logger.Info("Button Press Event")
			xevent.Quit(X)
		}).Connect(X, X.RootWin())

	xevent.KeyPressFun(
		func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			value := parseKeyEnvent(X, e.State, e.Detail)
			pressKeyStr = value
			dbus.Emit(m, "KeyPressEvent", value)
		}).Connect(X, X.RootWin())

	xevent.KeyReleaseFun(
		func(X *xgbutil.XUtil, e xevent.KeyReleaseEvent) {
			if strings.ToLower(pressKeyStr) == "super_l" ||
				strings.ToLower(pressKeyStr) == "super_r" {
				pressKeyStr = "Super"
			}

			dbus.Emit(m, "KeyReleaseEvent", pressKeyStr)
			pressKeyStr = ""
			ungrabAllMouseButton(X)
			keybind.UngrabKeyboard(X)
			logger.Infof("Key: %s\n", pressKeyStr)
			xevent.Quit(X)
		}).Connect(X, X.RootWin())

	xevent.Main(X)
	//}()
}
// connect is essentially 'Connect' for either KeyPress or KeyRelease events.
// Namely, it parses the key string, issues a grab request if necessary,
// sets up the appropriate event handlers for the main event loop, and attaches
// the callback to the keybinding state.
func connect(xu *xgbutil.XUtil, callback xgbutil.CallbackKey,
	evtype int, win xproto.Window, keyStr string, grab, reconnect bool) error {

	// Get the mods/key first
	mods, keycodes, err := ParseString(xu, keyStr)
	if err != nil {
		return err
	}

	// Only do the grab if we haven't yet on this window.
	for _, keycode := range keycodes {
		if grab && keyBindGrabs(xu, evtype, win, mods, keycode) == 0 {
			if err := GrabChecked(xu, win, mods, keycode); err != nil {
				// If a bad access, let's be nice and give a good error message.
				switch err.(type) {
				case xproto.AccessError:
					return fmt.Errorf("Got a bad access error when trying to "+
						"bind '%s'. This usually means another client has "+
						"already grabbed this keybinding.", keyStr)
				default:
					return fmt.Errorf("Could not bind '%s' because: %s",
						keyStr, err)
				}
			}
		}

		// If we've never grabbed anything on this window before, we need to
		// make sure we can respond to it in the main event loop.
		// Never do this if we're reconnecting.
		if !reconnect {
			var allCb xgbutil.Callback
			if evtype == xevent.KeyPress {
				allCb = xevent.KeyPressFun(runKeyPressCallbacks)
			} else {
				allCb = xevent.KeyReleaseFun(runKeyReleaseCallbacks)
			}

			// If this is the first Key{Press|Release}Event on this window,
			// then we need to listen to Key{Press|Release} events in the main
			// loop.
			if !connectedKeyBind(xu, evtype, win) {
				allCb.Connect(xu, win)
			}
		}

		// Finally, attach the callback.
		attachKeyBindCallback(xu, evtype, win, mods, keycode, callback)
	}

	// Keep track of all unique key connections.
	if !reconnect {
		addKeyString(xu, callback, evtype, win, keyStr, grab)
	}

	return nil
}
Beispiel #4
0
func (m *Manager) listenKeyEvents() {
	xevent.KeyPressFun(
		func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			modStr := keybind.ModifierString(e.State)
			keyStr := keybind.LookupString(X, e.State, e.Detail)
			if e.Detail == 65 {
				keyStr = "space"
			}
			logger.Infof("KeyStr: %s, modStr: %s", keyStr, modStr)
			if !m.mediaKey.emitMediaSignal(modStr, keyStr, true) {
				modStr = deleteSpecialMod(modStr)
				value := ""
				if len(modStr) < 1 {
					value = keyStr
				} else {
					value = modStr + "-" + keyStr
				}

				info, ok := newKeycodeInfo(value)
				if !ok {
					return
				}

				if v, ok := getExecCommand(info); ok {
					// 不然按键会阻塞,直到程序推出
					go doAction(v)
				}
			}
		}).Connect(X, X.RootWin())

	xevent.KeyReleaseFun(
		func(X *xgbutil.XUtil, e xevent.KeyReleaseEvent) {
			modStr := keybind.ModifierString(e.State)
			keyStr := keybind.LookupString(X, e.State, e.Detail)
			if e.Detail == 65 {
				keyStr = "space"
			}
			//modStr = deleteSpecialMod(modStr)
			m.mediaKey.emitMediaSignal(modStr, keyStr, false)
		}).Connect(X, X.RootWin())
}