我目前正在通过 Alfred 运行 GUI AppleScript 来切换输入源,而 GUI 脚本有时可能需要 1 秒才能完成更改。有时会很烦人。
我在终端/脚本中遇到了确定 OS X 键盘布局(“输入源”)。我想知道,因为如果有办法以编程方式更改输入源,我们可以找出当前的输入源吗?我试过覆盖 com.apple.HIToolbox.plist 但它不会改变输入。
(我确实意识到系统首选项中有输入源的映射快捷方式,但是我更喜欢使用 Alfred 映射关键字)
我目前正在通过 Alfred 运行 GUI AppleScript 来切换输入源,而 GUI 脚本有时可能需要 1 秒才能完成更改。有时会很烦人。
我在终端/脚本中遇到了确定 OS X 键盘布局(“输入源”)。我想知道,因为如果有办法以编程方式更改输入源,我们可以找出当前的输入源吗?我试过覆盖 com.apple.HIToolbox.plist 但它不会改变输入。
(我确实意识到系统首选项中有输入源的映射快捷方式,但是我更喜欢使用 Alfred 映射关键字)
您可以使用文本输入服务 API 来做到这一点:
NSArray* sources = CFBridgingRelease(TISCreateInputSourceList((__bridge CFDictionaryRef)@{ (__bridge NSString*)kTISPropertyInputSourceID : @"com.apple.keylayout.French" }, FALSE));
TISInputSourceRef source = (__bridge TISInputSourceRef)sources[0];
OSStatus status = TISSelectInputSource(source);
if (status != noErr)
/* handle error */;
第一行中的字典可以将其他属性用于选择输入源的其他标准。
还有NSTextInputContext
。它有一个selectedKeyboardInputSource
可以设置为输入源 ID 以选择不同的输入源。那里的问题是您需要一个实例NSTextInputContext
来使用,并且其中一个实例仅在您有一个带有文本视图作为其第一响应者的关键窗口时才存在。
@Ken Thomases 的解决方案可能是最强大的——但它需要创建一个命令行实用程序。
不幸的是,非 GUI 脚本 shell 脚本/AppleScripting 解决方案不是一个选项:虽然可以更新反映当前所选输入源(键盘布局)的文件 -系统将忽略更改。*.plist
~/Library/Preferences/com.apple.HIToolbox.plist
但是,以下GUI 脚本解决方案(基于this)虽然仍然涉及可见动作,但在我的机器上是健壮且相当快的(大约 0.2 秒):
(如果您只是想循环浏览已安装的布局,使用系统偏好设置中定义的键盘快捷键可能是您最好的选择;此解决方案的优点是您可以针对特定布局。)
请注意评论中提到的先决条件。
# Example call
my switchToInputSource("Spanish")
# Switches to the specified input source (keyboard layout) using GUI scripting.
# Prerequisites:
# - The application running this script must be granted assisistive access.
# - Showing the Input menu in the menu bar must be turned on
# (System Preferences > Keyboard > Input Sources > Show Input menu in menu bar).
# Parameters:
# name ... input source name, as displayed when you open the Input menu from
# the menu bar; e.g.: "U.S."
# Example:
# my switchToInputSource("Spanish")
on switchToInputSource(name)
tell application "System Events" to tell process "SystemUIServer"
tell (menu bar item 1 of menu bar 1 whose description is "text input")
# !! Sadly, we must *visibly* select (open) the text-input menu-bar extra in order to
# !! populate its menu with the available input sources.
select
tell menu 1
# !! Curiously, using just `name` instead of `(get name)` didn't work: 'Access not allowed'.
click (first menu item whose title = (get name))
end tell
end tell
end tell
end switchToInputSource
对于那些想要构建@Ken Thomases 的解决方案但没有安装 Xcode(这是几个 GiB 并且除非认真使用,否则花费这么多空间完全没用)的人,可以使用 Xcode 命令行工具来构建它。
互联网上有几个关于如何安装 Xcode 命令行工具的教程。这里的要点是,与成熟的 Xcode 相比,它只占用了一小部分空间。
安装完成后,步骤如下:
#include <Carbon/Carbon.h>
int main (int argc, const char * argv[]) {
NSArray* sources = CFBridgingRelease(TISCreateInputSourceList((__bridge CFDictionaryRef)@{ (__bridge NSString*)kTISPropertyInputSourceID : @"com.apple.keylayout.French" }, FALSE));
TISInputSourceRef source = (__bridge TISInputSourceRef)sources[0];
OSStatus status = TISSelectInputSource(source);
if (status != noErr)
return -1;
return 0;
}
French
为您想要的布局。clang -framework Carbon whatever.m -o whatever
您的应用程序是whatever
在同一文件夹中创建的,可以按以下方式执行:
.\whatever
我从未创建过任何 Objective-C 程序,所以这可能不是最理想的,但我想要一个可以将键盘布局作为命令行参数的可执行文件。对于任何有兴趣的人,这是我想出的解决方案:
在第 2 步中使用此代码:
#import <Foundation/Foundation.h>
#include <Carbon/Carbon.h>
int main (int argc, const char * argv[]) {
NSArray *arguments = [[NSProcessInfo processInfo] arguments];
NSArray* sources = CFBridgingRelease(TISCreateInputSourceList((__bridge CFDictionaryRef)@{ (__bridge NSString*)kTISPropertyInputSourceID : [@"com.apple.keylayout." stringByAppendingString:arguments[1]] }, FALSE));
TISInputSourceRef source = (__bridge TISInputSourceRef)sources[0];
OSStatus status = TISSelectInputSource(source);
if (status != noErr)
return -1;
return 0;
}
在第 6 步中,运行以下命令:
clang -framework Carbon -framework Foundation whatever.m -o whatever
您现在可以从命令行切换到任何布局,例如:
./whatever British
注意:它只允许切换到系统上已经配置的布局!
另一种选择是使用 Swift。它可以以类似脚本的方式使用(无需编译)。
swift script_file_name
代码:
import Carbon
let command = ProcessInfo.processInfo.arguments.dropFirst().last ?? ""
let filter = command == "list" ? nil : [kTISPropertyInputSourceID: command]
guard let cfSources = TISCreateInputSourceList(filter as CFDictionary?, false),
let sources = cfSources.takeRetainedValue() as? [TISInputSource] else {
print("Use \"list\" as an argument to list all enabled input sources.")
exit(-1)
}
if filter == nil { // Print all sources
print("Change input source by passing one of these names as an argument:")
sources.forEach {
let cfID = TISGetInputSourceProperty($0, kTISPropertyInputSourceID)!
print(Unmanaged<CFString>.fromOpaque(cfID).takeUnretainedValue() as String)
}
} else if let firstSource = sources.first { // Select this source
exit(TISSelectInputSource(firstSource))
}
这详细说明了Ken Thomases和sbnc.eu的答案。
在 AppleScript 上,您只能使用 cmd + "space" (或其他东西,用于更改键盘源)。
和所有你需要的:
key code 49 using command down
49 - AppleScript ASCII 中的“空格”按钮代码。
PS:不要忘记在系统偏好设置中访问 AppleScript 实用程序。
tell application "System Events"
key code 49 using control down
end tell
通过按键更改布局