qemu/kvm(virtual machine manger) windows10虚拟机和i3wm win+num 切换workspace冲突问题大家有解决过吗?(已解决)

我使用i3wm,在使用windwos10虚拟机的时候想使用win+num切换workspace. 但是在虚拟机里按win+num会调用win10的快捷键,在网上搜索之后禁用了windows10里的 win+num按键,但是还是不能切换workspace.

想问问大家有解决过这个问题吗?

想过,没能解决

几个思路

  1. 自己在 windows guest 里写个东西和 host 通信,把 guest 中的 super+<NUM> 翻译成 i3-msg workspace <NUM> 并传出来
  2. 换 wayland
  3. 把 super key 绑成 host key,然后使用 super super-<NUM> 来切换桌面

谢谢,我试试看

我的alt键和win键是互换的,但依然会有冲突,又在windows中用 AutoHotkey改了其他键位。但现在不那么折腾了,你可以试试。

我试了@aeghn 的解决方案,host key 是可以的就是有点别扭。

  1. 自己在 windows guest 里写个东西和 host 通信,把 guest 中的 super+<NUM> 翻译成 i3-msg workspace <NUM> 并传出来

这个方案已经在guest用pyhook实现对按键的监听了,剩下的就是和host通信了。

  1. 自己在 windows guest 里写个东西和 host 通信,把 guest 中的 super+<NUM> 翻译成 i3-msg workspace <NUM> 并传出来

这个我已经实现了,遗留问题是guest获取host ip的问题,现在先手动填一下。

记录一下解决方案:

host: 使用node实现了一个简陋的http服务

'use strict';

const util = require('util');
const child_process = require('child_process');
const exec = util.promisify(child_process.exec);

const http = require('http');
const url = require('url');
const qs = require('querystring')
const server = http.createServer((req, res) => {
  //使用此回调处理每个单独的请求。
  const urlobj = url.parse(req.url)
  console.log(urlobj);
  if (urlobj.query) {
    const query = qs.parse(urlobj.query);
    console.log(query);
    const sendkey = query.sendkey;
    if (/^Lwin(\d|10)?$/.test(sendkey)) {
      const command = 'i3-msg workspace ' + sendkey.replace('Lwin', '');
      console.log(command);
      exec(command)
        .then(console.log)
        .catch(console.error);
    }
  }
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');

}).listen(8888)

console.log('Server running at http://127.0.0.1:8888/');

guest:

使用pyHook监听windows全局键盘事件,判断是win + num 发送http请求到host.

依赖:

  • pyHook(python3.7) download
  • pywin32
  • requests
import pythoncom
import pyHook
import re
import requests

def sendkeyToHost(key):
    """调用host接口切换workspace"""
    host_ip = 'http://10.157.134.144:8888/xxx'
    payload = {'sendkey': key}
    r = requests.get(host_ip, payload)
    print(r)


# 记录当前按键
pyHook.wfcurrent_key = ""

def OnKeyboardDownEvent(event):
    """监听KeyboardDownEvent,判断是否是 win + num,如果是发送请求给host"""
    # print('OnKeyboardDownEvent => wfcurrent_key: {},  key {}, keyid, {}'.format(
    #     pyHook.wfcurrent_key, event.Key, event.KeyID))
    if event.Key == '0':
        pyHook.wfcurrent_key += '10'
    else:
        pyHook.wfcurrent_key += event.Key
    if re.match(r'^Lwin(\d|10)$', pyHook.wfcurrent_key):
        print('send:', pyHook.wfcurrent_key)
        sendkeyToHost(pyHook.wfcurrent_key)
        return False
    # return True to pass the event to other handlers
    return True

def OnKeyboardUpEvent(event):
    """
    监听KeyboardUpEvent, 清除记录的按键
    这边会有bug,跳到其他workspace时,所以按键都会触发UP事件,就算实际没有放开win键
    """
    # print('OnKeyboardUpEvent', event.KeyID, event.Key)
    key = ''
    if event.Key == '0':
        key = '10'
    else:
        key = event.Key
    pyHook.wfcurrent_key = pyHook.wfcurrent_key.replace(key, '')
    return True

# create a hook manager
hm = pyHook.HookManager()
# watch for all mouse events
hm.KeyDown = OnKeyboardDownEvent
hm.KeyUp = OnKeyboardUpEvent
# set the hook2123456778
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()

我也整了一个(甚至不是 demo,仅作想法,不过可以工作)

guest(autohotkey)

SwitchI3Workspace(wid) {
    ip := "http://192.168.122.1:10999"

    req := ip
    . "/workspace"
    . "/"
    . wid

    whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
    whr.Open("GET", req)
    whr.Send()
    return
}

#1::SwitchI3Workspace("1")
#2::SwitchI3Workspace("2")
#3::SwitchI3Workspace("3")
#4::SwitchI3Workspace("4")
#5::SwitchI3Workspace("5")
#6::SwitchI3Workspace("6")
#7::SwitchI3Workspace("7")
#8::SwitchI3Workspace("8")

host(python)

#!/usr/bin/env python

from bottle import run, get
from i3ipc import Connection


i3 = Connection()

@get('/workspace/<id>')
def workspace(id):
    i3.command('workspace ' + id)


run(host='0.0.0.0', port=10999, debug=True)
1 个赞

参考你的demo, 我做了些更改基本能正常使用了。

解决了几个问题:

  1. host固定ip。
  2. host web 服务 开机自启动。
  3. guest autohotkey 开机自启动。

我记录了一下,https://archer-n.github.io/posts/在-windows-10-虚拟机中切换-i3-工作区/

还有一个更简单的方法,使用 xkeysnail 之类的软件

配置参考:

# Keybindings for Firefox/Chrome
define_keymap(re.compile("Virt-manager"), {
    # Ctrl+Alt+j/k to switch next/previous tab
    K("Super-KEY_1"): launch(["i3-msg", "workspace", "1"]),
    K("Super-KEY_2"): launch(["i3-msg", "workspace", "2"]),
    K("Super-KEY_3"): launch(["i3-msg", "workspace", "3"]),
    K("Super-KEY_4"): launch(["i3-msg", "workspace", "4"]),
    K("Super-KEY_5"): launch(["i3-msg", "workspace", "5"]),
    K("Super-KEY_6"): launch(["i3-msg", "workspace", "6"]),
    K("Super-KEY_7"): launch(["i3-msg", "workspace", "7"]),
    K("Super-KEY_8"): launch(["i3-msg", "workspace", "8"])

}, "Windows guest")

赞,这个很有效 :grinning: