Created
October 21, 2016 03:47
-
-
Save Khande/76f24ba90607fb5d54185bd8e4520de6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
# coding: utf-8 | |
''' | |
auto switch keyboard between different applications | |
if you want to change the app list, modify the var 'ignore_list' | |
一定要用系统自带的 python, 用 brew 或其他方式安装的 python 不能识别 AppKit 等模块,花了很长时间在 pyobjc 的文档中看到这样一句话: | |
The system version of Python (``/usr/bin/python``) includes a copy of | |
PyObjC starting at MacOSX 10.5 ("Leopard"). Installing other versions | |
of PyObjC with "/usr/bin/python" on Leopard or later is not supported | |
and could break your system. | |
相见恨晚啊! | |
用了 brew install python 的直接 brew uninstall python 即可,就是 python 不能使用最新版。 | |
''' | |
from AppKit import NSWorkspace, NSWorkspaceDidActivateApplicationNotification, NSWorkspaceApplicationKey | |
from Foundation import NSObject | |
from PyObjCTools import AppHelper | |
import ctypes | |
import ctypes.util | |
import objc | |
import CoreFoundation | |
import AppKit | |
info = AppKit.NSBundle.mainBundle().infoDictionary() | |
info["LSBackgroundOnly"] = "1" | |
# add your custom apps here, check the bundle id in /Application/xx.app/Contents/info.plist | |
ignore_list = [ | |
"com.googlecode.iterm2", | |
"com.runningwithcrayons.Alfred-2", | |
"com.runningwithcrayons.Alfred-3", | |
"com.apple.Spotlight", | |
"com.jetbrains.intellij.ce-EAP", | |
"com.google.android.studio", | |
"com.sublimetext.3", | |
"com.github.atom" | |
] | |
carbon = ctypes.cdll.LoadLibrary(ctypes.util.find_library('Carbon')) | |
_objc = ctypes.PyDLL(objc._objc.__file__) | |
# PyObject *PyObjCObject_New(id objc_object, int flags, int retain) | |
_objc.PyObjCObject_New.restype = ctypes.py_object | |
_objc.PyObjCObject_New.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int] | |
def objc_object(id): | |
return _objc.PyObjCObject_New(id, 0, 1) | |
# kTISPropertyLocalizedName | |
kTISPropertyUnicodeKeyLayoutData_p = ctypes.c_void_p.in_dll(carbon, 'kTISPropertyInputSourceIsEnabled') | |
kTISPropertyInputSourceLanguages_p = ctypes.c_void_p.in_dll(carbon, 'kTISPropertyInputSourceLanguages') | |
kTISPropertyInputSourceType_p = ctypes.c_void_p.in_dll(carbon, 'kTISPropertyInputSourceType') | |
kTISPropertyLocalizedName_p = ctypes.c_void_p.in_dll(carbon, 'kTISPropertyLocalizedName') | |
# kTISPropertyInputSourceLanguages_p = ctypes.c_void_p.in_dll(carbon, 'kTISPropertyInputSourceLanguages') | |
kTISPropertyInputSourceCategory = objc_object(ctypes.c_void_p.in_dll(carbon, 'kTISPropertyInputSourceCategory')) | |
kTISCategoryKeyboardInputSource = objc_object(ctypes.c_void_p.in_dll(carbon, 'kTISCategoryKeyboardInputSource')) | |
# TISCreateInputSourceList | |
carbon.TISCreateInputSourceList.restype = ctypes.c_void_p | |
carbon.TISCreateInputSourceList.argtypes = [ctypes.c_void_p, ctypes.c_bool] | |
carbon.TISSelectInputSource.restype = ctypes.c_void_p | |
carbon.TISSelectInputSource.argtypes = [ctypes.c_void_p] | |
carbon.TISGetInputSourceProperty.argtypes = [ctypes.c_void_p, ctypes.c_void_p] | |
carbon.TISGetInputSourceProperty.restype = ctypes.c_void_p | |
# carbon.TISCopyCurrentKeyboardLayoutInputSource.argtypes = [] | |
# carbon.TISCopyCurrentKeyboardLayoutInputSource.restype = ctypes.c_void_p | |
carbon.TISCopyInputSourceForLanguage.argtypes = [ctypes.c_void_p] | |
carbon.TISCopyInputSourceForLanguage.restype = ctypes.c_void_p | |
def get_avaliable_languages(): | |
single_langs = filter(lambda x: x.count() == 1, \ | |
map(lambda x: objc_object(carbon.TISGetInputSourceProperty(CoreFoundation.CFArrayGetValueAtIndex(objc_object(s), x).__c_void_p__(), kTISPropertyInputSourceLanguages_p)), \ | |
range(CoreFoundation.CFArrayGetCount(objc_object(carbon.TISCreateInputSourceList(None, 0)))))) | |
res = set() | |
map(lambda y: res.add(y[0]), single_langs) | |
return res | |
def select_kb(lang): | |
cur = carbon.TISCopyInputSourceForLanguage(CoreFoundation.CFSTR(lang).__c_void_p__()) | |
carbon.TISSelectInputSource(cur) | |
class Observer(NSObject): | |
def handle_(self, noti): | |
info = noti.userInfo().objectForKey_(NSWorkspaceApplicationKey) | |
bundleIdentifier = info.bundleIdentifier() | |
if bundleIdentifier in ignore_list: | |
#print "found: %s active" % bundleIdentifier | |
select_kb(u'en') | |
def main(): | |
nc = NSWorkspace.sharedWorkspace().notificationCenter() | |
observer = Observer.new() | |
nc.addObserver_selector_name_object_( | |
observer, | |
"handle:", | |
NSWorkspaceDidActivateApplicationNotification, | |
None | |
) | |
AppHelper.runConsoleEventLoop(installInterrupt=True) | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
我始终在报错,我的系统是10.9.5的,用的系统自带的Python 2.7,请问你知道是什么问题吗?
found: com.googlecode.iterm2 active
Traceback (most recent call last):
File "auto_switch_kb.py", line 100, in <module>
main()
File "auto_switch_kb.py", line 98, in main
AppHelper.runConsoleEventLoop(installInterrupt=True)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC/PyObjCTools/AppHelper.py", line 178, in runConsoleEventLoop
if not runLoop.runMode_beforeDate_(mode, nextfire):
File "auto_switch_kb.py", line 84, in handle_
select_kb(u'US')
File "auto_switch_kb.py", line 75, in select_kb
cur = carbon.TISCopyInputSourceForLanguage(CoreFoundation.CFSTR(lang).__c_void_p__())
AttributeError: '__NSCFString' object has no attribute '__c_void_p__'