Skip to content

Instantly share code, notes, and snippets.

@tiann
Created December 2, 2015 06:51
Show Gist options
  • Save tiann/f85e89bef4b6e9b83f2a to your computer and use it in GitHub Desktop.
Save tiann/f85e89bef4b6e9b83f2a to your computer and use it in GitHub Desktop.
auto switch keyboard to english in specific applications
#! /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'
'''
from AppKit import NSWorkspace, NSWorkspaceDidActivateApplicationNotification, NSWorkspaceApplicationKey
from Foundation import NSObject
from PyObjCTools import AppHelper
import ctypes
import ctypes.util
import objc
import CoreFoundation
# 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.jetbrains.intellij.ce-EAP"
]
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()
@johnwatsondev
Copy link

It will be great if can change the custom input source rather than by language type. Because of that, I have a custom input source layout.

Eg: I want to change to U.S.custom input source.
2016-06-01 17 29 43

@XiYeLv
Copy link

XiYeLv commented Jul 26, 2017

厉害了……

@DeanLXY
Copy link

DeanLXY commented Aug 18, 2018

如果是安装搜狗输入法, select_kb(u'en'),这个会切换到默认输入法的英文输入。怎么能切到搜狗的英文输入
感谢

@too
Copy link

too commented Mar 22, 2019

直接跑起来似乎可用啊,不错!

@iam-frankqiu
Copy link

如果是安装搜狗输入法, select_kb(u'en'),这个会切换到默认输入法的英文输入。怎么能切到搜狗的英文输入
感谢

我也想问这个问题

@gooqiao
Copy link

gooqiao commented Sep 23, 2019

有什么方法在输入框获得焦点带时候悬浮显示当前输入法吗?我想这样就不会再敲错了。

@osaso
Copy link

osaso commented Oct 14, 2019

怎么使用?

@cocobear
Copy link

有什么方法在输入框获得焦点带时候悬浮显示当前输入法吗?我想这样就不会再敲错了。

确实有这样的功能的话会很方便。有这么个软件:https://showyedge.pqrs.org/
是把输入法的状态显示在了窗口最上面。感觉不是很方便。

@typoman
Copy link

typoman commented Aug 9, 2022

It used to work but it has stopped with new OSX (12.5.). Gives this error:

Traceback (most recent call last):
  File "tmp.py", line 32, in <module>
    _objc.PyObjCObject_New.restype = ctypes.py_object
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/ctypes/__init__.py", line 387, in __getattr__
    func = self.__getitem__(name)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/ctypes/__init__.py", line 392, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
AttributeError: dlsym(0x210f6b5c0, PyObjCObject_New): symbol not found

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment