本文目录导读:

- Linux (X11) - 使用 setxkbmap
- Linux (Wayland) - 使用 ydotool
- Windows - PowerShell 脚本
- macOS - AppleScript + Shell
- 更高级的方案 - 使用 Python
- 使用方法
- 注意事项
Linux (X11) - 使用 setxkbmap
根据应用窗口切换
#!/bin/bash
# 监听窗口焦点变化并切换键盘布局
# 定义应用对应的键盘布局
declare -A APP_LAYOUTS
APP_LAYOUTS["firefox"]="us"
APP_LAYOUTS["code"]="us"
APP_LAYOUTS["terminal"]="de"
APP_LAYOUTS["slack"]="fr"
# 获取当前活动窗口的信息
get_active_window_info() {
xdotool getactivewindow getwindowname
}
# 切换键盘布局
switch_layout() {
local app_name="$1"
local layout="${APP_LAYOUTS[$app_name]}"
if [[ -n "$layout" ]]; then
setxkbmap "$layout"
echo "切换到 $layout 布局"
fi
}
# 主循环
while true; do
current_app=$(get_active_window_info)
# 提取应用程序名称(小写)
app_lower=$(echo "$current_app" | tr '[:upper:]' '[:lower:]')
# 检查是否有匹配的应用
for app in "${!APP_LAYOUTS[@]}"; do
if [[ "$app_lower" == *"$app"* ]]; then
switch_layout "$app"
break
fi
done
sleep 0.5
done
Linux (Wayland) - 使用 ydotool
#!/bin/bash
# Wayland 环境下的键盘布局切换
# 安装依赖
# sudo apt install ydotool
switch_layout_wayland() {
local layout="$1"
case "$layout" in
"us")
gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us')]"
;;
"de")
gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'de')]"
;;
"fr")
gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'fr')]"
;;
esac
}
# 根据时间切换(示例)
while true; do
hour=$(date +%H)
if [ "$hour" -ge 9 ] && [ "$hour" -lt 18 ]; then
# 工作时间使用英文布局
switch_layout_wayland "us"
else
# 休息时间使用母语布局
switch_layout_wayland "de"
fi
sleep 3600 # 每小时检查一次
done
Windows - PowerShell 脚本
# 自动切换键盘布局脚本
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class KeyboardLayout {
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
public static extern IntPtr GetKeyboardLayout(uint idThread);
[DllImport("user32.dll")]
public static extern IntPtr ActivateKeyboardLayout(IntPtr hkl, uint flags);
}
"@
function Get-ActiveProcessName {
$hwnd = [KeyboardLayout]::GetForegroundWindow()
$null = [KeyboardLayout]::GetWindowThreadProcessId($hwnd, [ref]$pid)
return (Get-Process -Id $pid).ProcessName
}
function Set-KeyboardLayout {
param([string]$LayoutName)
# 布局ID映射
$layouts = @{
"US" = 0x04090409
"DE" = 0x04070407
"FR" = 0x040C040C
}
if ($layouts.ContainsKey($LayoutName)) {
$hkl = [IntPtr]::new($layouts[$LayoutName])
[KeyboardLayout]::ActivateKeyboardLayout($hkl, 0)
}
}
# 主循环
while ($true) {
$processName = Get-ActiveProcessName
switch -Wildcard ($processName) {
"chrome*" { Set-KeyboardLayout "US" }
"firefox*" { Set-KeyboardLayout "US" }
"notepad*" { Set-KeyboardLayout "US" }
"devenv*" { Set-KeyboardLayout "US" }
"*word*" { Set-KeyboardLayout "FR" }
"*excel*" { Set-KeyboardLayout "FR" }
default { Set-KeyboardLayout "DE" }
}
Start-Sleep -Milliseconds 500
}
macOS - AppleScript + Shell
#!/bin/bash
# macOS 键盘布局切换脚本
# 获取当前活动应用
get_active_app() {
osascript -e 'tell application "System Events" to get name of first process whose frontmost is true'
}
# 切换输入源
switch_input_source() {
local layout="$1"
case "$layout" in
"US")
osascript -e 'tell application "System Events" to tell process "SystemUIServer" to click menu bar item 1 of menu bar 2'
;;
"German")
osascript -e 'tell application "System Events" to tell process "SystemUIServer" to click menu bar item 2 of menu bar 2'
;;
"French")
osascript -e 'tell application "System Events" to tell process "SystemUIServer" to click menu bar item 3 of menu bar 2'
;;
esac
}
# 配置应用-布局映射
declare -A APP_LAYOUTS
APP_LAYOUTS["Safari"]="US"
APP_LAYOUTS["Chrome"]="US"
APP_LAYOUTS["Terminal"]="US"
APP_LAYOUTS["Xcode"]="US"
APP_LAYOUTS["TextEdit"]="German"
APP_LAYOUTS["Pages"]="French"
while true; do
current_app=$(get_active_app)
if [[ -n "${APP_LAYOUTS[$current_app]}" ]]; then
switch_input_source "${APP_LAYOUTS[$current_app]}"
fi
sleep 0.5
done
更高级的方案 - 使用 Python
#!/usr/bin/env python3
"""
跨平台键盘布局自动切换器
"""
import platform
import time
import subprocess
import re
class KeyboardLayoutSwitcher:
def __init__(self):
self.system = platform.system()
self.setup_layout_mapping()
def setup_layout_mapping(self):
"""定义应用和布局的映射关系"""
self.layout_map = {
# 应用名关键词: 布局名
'browser': 'us', # 浏览器
'terminal': 'us', # 终端
'code': 'us', # 编程IDE
'office': 'fr', # 办公软件
'chat': 'de', # 聊天软件
'default': 'us' # 默认布局
}
# 具体应用映射
self.app_map = {
'firefox': 'browser',
'chrome': 'browser',
'safari': 'browser',
'terminal': 'terminal',
'iterm2': 'terminal',
'vscode': 'code',
'code': 'code',
'word': 'office',
'excel': 'office',
'slack': 'chat',
'telegram': 'chat',
'discord': 'chat',
}
def get_active_window_name(self):
"""获取当前活动窗口名称"""
if self.system == 'Linux':
try:
result = subprocess.run(
['xdotool', 'getactivewindow', 'getwindowname'],
capture_output=True, text=True
)
return result.stdout.strip().lower()
except:
return ''
elif self.system == 'Darwin': # macOS
try:
result = subprocess.run(
['osascript', '-e',
'tell application "System Events" to get name of first process whose frontmost is true'],
capture_output=True, text=True
)
return result.stdout.strip().lower()
except:
return ''
elif self.system == 'Windows':
try:
import win32gui
window = win32gui.GetForegroundWindow()
return win32gui.GetWindowText(window).lower()
except:
return ''
return ''
def switch_layout(self, layout):
"""切换键盘布局"""
if self.system == 'Linux':
subprocess.run(['setxkbmap', layout])
elif self.system == 'Darwin':
# macOS 切换输入源
script = f'''
tell application "System Events"
tell process "SystemUIServer"
click menu bar item 1 of menu bar 2
end tell
end tell
'''
subprocess.run(['osascript', '-e', script])
elif self.system == 'Windows':
# Windows 切换布局
import win32api
import win32con
layouts = {
'us': 0x04090409,
'de': 0x04070407,
'fr': 0x040C040C
}
if layout in layouts:
win32api.LoadKeyboardLayout(f'{layouts[layout]:08X}', win32con.KLF_ACTIVATE)
print(f"切换到 {layout} 布局")
def determine_layout(self, window_name):
"""根据窗口名称确定应使用的布局"""
window_lower = window_name.lower()
# 检查具体应用
for app, category in self.app_map.items():
if app in window_lower:
return self.layout_map.get(category, self.layout_map['default'])
# 检查关键词
for keyword, layout in self.layout_map.items():
if keyword in window_lower and keyword != 'default':
return layout
return self.layout_map['default']
def run(self):
"""主运行循环"""
print("键盘布局自动切换器已启动...")
last_layout = None
while True:
try:
window_name = self.get_active_window_name()
if window_name:
target_layout = self.determine_layout(window_name)
if target_layout != last_layout:
self.switch_layout(target_layout)
last_layout = target_layout
time.sleep(0.5) # 每0.5秒检查一次
except KeyboardInterrupt:
print("\n程序已停止")
break
except Exception as e:
print(f"错误: {e}")
time.sleep(2)
if __name__ == "__main__":
switcher = KeyboardLayoutSwitcher()
switcher.run()
使用方法
Linux 用户:
# 保存脚本为 switch_layout.sh chmod +x switch_layout.sh ./switch_layout.sh # 直接运行 # 或设置为开机自启动 # 添加到 ~/.bashrc 或使用 systemd
Windows 用户:
# 保存为 .ps1 文件 # 以管理员身份运行 PowerShell Set-ExecutionPolicy RemoteSigned .\keyboard_switcher.ps1
macOS 用户:
# 保存脚本 chmod +x keyboard_switcher.sh ./keyboard_switcher.sh
注意事项
- 权限问题:某些系统可能需要管理员权限
- 性能影响:建议将检查间隔设为0.5-1秒
- 自定义映射:根据自己的使用习惯修改应用-布局映射
- 调试建议:先使用
echo测试窗口检测功能
选择适合你系统的版本进行定制即可!
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播