├── bin └── xkbswitch ├── xkbswitch.xcodeproj ├── xcuserdata │ └── alecm.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ ├── xkbswitch.xcscheme │ │ └── xkbswitch_release.xcscheme ├── project.xcworkspace │ └── contents.xcworkspacedata └── project.pbxproj ├── README.md └── xkbswitch └── main.m /bin/xkbswitch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myshov/xkbswitch-macosx/HEAD/bin/xkbswitch -------------------------------------------------------------------------------- /xkbswitch.xcodeproj/xcuserdata/alecm.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /xkbswitch.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /xkbswitch.xcodeproj/xcuserdata/alecm.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | xkbswitch.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | xkbswitch_release.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | B0053B9F1A56B1AE00B2EB8F 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xkbswitch-macosx 2 | 3 | Console keyboard layout switcher for Mac OS X. 4 | 5 | The utility for switching current layout in terminal. You can use it whenever you need 6 | that functionality (for example, for tmux statusline when one is running in fullscreen 7 | terminal). Also you can use it as auxilary utility for [vim-xkbswitch](https://github.com/lyokha/vim-xkbswitch) plugin for 8 | changing the keyboard layout in Mac OS X. The utility should work on all versions 9 | of Mac OS X since 10.6. 10 | 11 | ## Vim integration 12 | For integration with vim-xkbswitch you need to install this [library](https://github.com/myshov/libxkbswitch-macosx) and follow instructions from there. 13 | 14 | ## Installation 15 | For installation put executable file from bin directory in any directory in your $PATH 16 | variable. For example you can put it into `/usr/local/bin` with this command (if source 17 | files of utility in your `Download` directory): 18 | ```shell 19 | $ cp ~/Download/xkbswitch-macosx/bin/xkbswitch /usr/local/bin 20 | ``` 21 | ## Usage: 22 | ``` 23 | xkbswitch -g|s [-n|e] [value] 24 | where: 25 | -g - get number of layout 26 | -s - set layout by number of list of layouts 27 | -n - code mode (default mode) 28 | -e - string mode (combine it with -g|s to get current layout name or set layouts by its name) 29 | -l - list all available keyboard layouts (their names) 30 | ``` 31 | 32 | ## Examples: 33 | #### set layout: 34 | ```shell 35 | $ ./xkbswitch -se RussianWin 36 | $ ./xkbswitch -se US 37 | $ ./xkbswitch -s 2 38 | $ ./xkbswitch -s 1 39 | ``` 40 | 41 | #### get current layout: 42 | ```shell 43 | $ ./xkbswitch -ge 44 | $ ./xkbswitch -g 45 | ``` 46 | 47 | ## License 48 | The MIT License (MIT) 49 | 50 | Copyright (c) 2015 Alexander Myshov 51 | 52 | Permission is hereby granted, free of charge, to any person obtaining a copy 53 | of this software and associated documentation files (the "Software"), to deal 54 | in the Software without restriction, including without limitation the rights 55 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 56 | copies of the Software, and to permit persons to whom the Software is 57 | furnished to do so, subject to the following conditions: 58 | 59 | The above copyright notice and this permission notice shall be included in all 60 | copies or substantial portions of the Software. 61 | 62 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 63 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 64 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 65 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 66 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 67 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 68 | SOFTWARE. 69 | -------------------------------------------------------------------------------- /xkbswitch.xcodeproj/xcuserdata/alecm.xcuserdatad/xcschemes/xkbswitch.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /xkbswitch.xcodeproj/xcuserdata/alecm.xcuserdatad/xcschemes/xkbswitch_release.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /xkbswitch.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B0053BA41A56B1AE00B2EB8F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B0053BA31A56B1AE00B2EB8F /* main.m */; }; 11 | B0053BAB1A56B41800B2EB8F /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0053BAA1A56B41800B2EB8F /* Carbon.framework */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | B0053B9E1A56B1AE00B2EB8F /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = /usr/share/man/man1/; 19 | dstSubfolderSpec = 0; 20 | files = ( 21 | ); 22 | runOnlyForDeploymentPostprocessing = 1; 23 | }; 24 | /* End PBXCopyFilesBuildPhase section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | B0053BA01A56B1AE00B2EB8F /* xkbswitch */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xkbswitch; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | B0053BA31A56B1AE00B2EB8F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 29 | B0053BAA1A56B41800B2EB8F /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; 30 | /* End PBXFileReference section */ 31 | 32 | /* Begin PBXFrameworksBuildPhase section */ 33 | B0053B9D1A56B1AE00B2EB8F /* Frameworks */ = { 34 | isa = PBXFrameworksBuildPhase; 35 | buildActionMask = 2147483647; 36 | files = ( 37 | B0053BAB1A56B41800B2EB8F /* Carbon.framework in Frameworks */, 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | B0053B971A56B1AE00B2EB8F = { 45 | isa = PBXGroup; 46 | children = ( 47 | B0053BAA1A56B41800B2EB8F /* Carbon.framework */, 48 | B0053BA21A56B1AE00B2EB8F /* xkbswitch */, 49 | B0053BA11A56B1AE00B2EB8F /* Products */, 50 | ); 51 | sourceTree = ""; 52 | }; 53 | B0053BA11A56B1AE00B2EB8F /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | B0053BA01A56B1AE00B2EB8F /* xkbswitch */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | B0053BA21A56B1AE00B2EB8F /* xkbswitch */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | B0053BA31A56B1AE00B2EB8F /* main.m */, 65 | ); 66 | path = xkbswitch; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXNativeTarget section */ 72 | B0053B9F1A56B1AE00B2EB8F /* xkbswitch */ = { 73 | isa = PBXNativeTarget; 74 | buildConfigurationList = B0053BA71A56B1AE00B2EB8F /* Build configuration list for PBXNativeTarget "xkbswitch" */; 75 | buildPhases = ( 76 | B0053B9C1A56B1AE00B2EB8F /* Sources */, 77 | B0053B9D1A56B1AE00B2EB8F /* Frameworks */, 78 | B0053B9E1A56B1AE00B2EB8F /* CopyFiles */, 79 | ); 80 | buildRules = ( 81 | ); 82 | dependencies = ( 83 | ); 84 | name = xkbswitch; 85 | productName = xkbswitch; 86 | productReference = B0053BA01A56B1AE00B2EB8F /* xkbswitch */; 87 | productType = "com.apple.product-type.tool"; 88 | }; 89 | /* End PBXNativeTarget section */ 90 | 91 | /* Begin PBXProject section */ 92 | B0053B981A56B1AE00B2EB8F /* Project object */ = { 93 | isa = PBXProject; 94 | attributes = { 95 | LastUpgradeCheck = 0610; 96 | ORGANIZATIONNAME = "Alexander Myshov"; 97 | TargetAttributes = { 98 | B0053B9F1A56B1AE00B2EB8F = { 99 | CreatedOnToolsVersion = 6.1.1; 100 | }; 101 | }; 102 | }; 103 | buildConfigurationList = B0053B9B1A56B1AE00B2EB8F /* Build configuration list for PBXProject "xkbswitch" */; 104 | compatibilityVersion = "Xcode 3.2"; 105 | developmentRegion = English; 106 | hasScannedForEncodings = 0; 107 | knownRegions = ( 108 | en, 109 | ); 110 | mainGroup = B0053B971A56B1AE00B2EB8F; 111 | productRefGroup = B0053BA11A56B1AE00B2EB8F /* Products */; 112 | projectDirPath = ""; 113 | projectRoot = ""; 114 | targets = ( 115 | B0053B9F1A56B1AE00B2EB8F /* xkbswitch */, 116 | ); 117 | }; 118 | /* End PBXProject section */ 119 | 120 | /* Begin PBXSourcesBuildPhase section */ 121 | B0053B9C1A56B1AE00B2EB8F /* Sources */ = { 122 | isa = PBXSourcesBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | B0053BA41A56B1AE00B2EB8F /* main.m in Sources */, 126 | ); 127 | runOnlyForDeploymentPostprocessing = 0; 128 | }; 129 | /* End PBXSourcesBuildPhase section */ 130 | 131 | /* Begin XCBuildConfiguration section */ 132 | B0053BA51A56B1AE00B2EB8F /* Debug */ = { 133 | isa = XCBuildConfiguration; 134 | buildSettings = { 135 | ALWAYS_SEARCH_USER_PATHS = NO; 136 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 137 | CLANG_CXX_LIBRARY = "libc++"; 138 | CLANG_ENABLE_MODULES = YES; 139 | CLANG_ENABLE_OBJC_ARC = YES; 140 | CLANG_WARN_BOOL_CONVERSION = YES; 141 | CLANG_WARN_CONSTANT_CONVERSION = YES; 142 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 143 | CLANG_WARN_EMPTY_BODY = YES; 144 | CLANG_WARN_ENUM_CONVERSION = YES; 145 | CLANG_WARN_INT_CONVERSION = YES; 146 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 147 | CLANG_WARN_UNREACHABLE_CODE = YES; 148 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 149 | COPY_PHASE_STRIP = NO; 150 | ENABLE_STRICT_OBJC_MSGSEND = YES; 151 | GCC_C_LANGUAGE_STANDARD = gnu99; 152 | GCC_DYNAMIC_NO_PIC = NO; 153 | GCC_OPTIMIZATION_LEVEL = 0; 154 | GCC_PREPROCESSOR_DEFINITIONS = ( 155 | "DEBUG=1", 156 | "$(inherited)", 157 | ); 158 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 159 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 160 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 161 | GCC_WARN_UNDECLARED_SELECTOR = YES; 162 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 163 | GCC_WARN_UNUSED_FUNCTION = YES; 164 | GCC_WARN_UNUSED_VARIABLE = YES; 165 | MACOSX_DEPLOYMENT_TARGET = 10.6; 166 | MTL_ENABLE_DEBUG_INFO = YES; 167 | ONLY_ACTIVE_ARCH = YES; 168 | SDKROOT = macosx; 169 | }; 170 | name = Debug; 171 | }; 172 | B0053BA61A56B1AE00B2EB8F /* Release */ = { 173 | isa = XCBuildConfiguration; 174 | buildSettings = { 175 | ALWAYS_SEARCH_USER_PATHS = NO; 176 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 177 | CLANG_CXX_LIBRARY = "libc++"; 178 | CLANG_ENABLE_MODULES = YES; 179 | CLANG_ENABLE_OBJC_ARC = YES; 180 | CLANG_WARN_BOOL_CONVERSION = YES; 181 | CLANG_WARN_CONSTANT_CONVERSION = YES; 182 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 183 | CLANG_WARN_EMPTY_BODY = YES; 184 | CLANG_WARN_ENUM_CONVERSION = YES; 185 | CLANG_WARN_INT_CONVERSION = YES; 186 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 187 | CLANG_WARN_UNREACHABLE_CODE = YES; 188 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 189 | COPY_PHASE_STRIP = YES; 190 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 191 | ENABLE_NS_ASSERTIONS = NO; 192 | ENABLE_STRICT_OBJC_MSGSEND = YES; 193 | GCC_C_LANGUAGE_STANDARD = gnu99; 194 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 195 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 196 | GCC_WARN_UNDECLARED_SELECTOR = YES; 197 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 198 | GCC_WARN_UNUSED_FUNCTION = YES; 199 | GCC_WARN_UNUSED_VARIABLE = YES; 200 | MACOSX_DEPLOYMENT_TARGET = 10.6; 201 | MTL_ENABLE_DEBUG_INFO = NO; 202 | ONLY_ACTIVE_ARCH = YES; 203 | SDKROOT = macosx; 204 | }; 205 | name = Release; 206 | }; 207 | B0053BA81A56B1AE00B2EB8F /* Debug */ = { 208 | isa = XCBuildConfiguration; 209 | buildSettings = { 210 | ONLY_ACTIVE_ARCH = YES; 211 | PRODUCT_NAME = "$(TARGET_NAME)"; 212 | }; 213 | name = Debug; 214 | }; 215 | B0053BA91A56B1AE00B2EB8F /* Release */ = { 216 | isa = XCBuildConfiguration; 217 | buildSettings = { 218 | ONLY_ACTIVE_ARCH = YES; 219 | PRODUCT_NAME = "$(TARGET_NAME)"; 220 | }; 221 | name = Release; 222 | }; 223 | /* End XCBuildConfiguration section */ 224 | 225 | /* Begin XCConfigurationList section */ 226 | B0053B9B1A56B1AE00B2EB8F /* Build configuration list for PBXProject "xkbswitch" */ = { 227 | isa = XCConfigurationList; 228 | buildConfigurations = ( 229 | B0053BA51A56B1AE00B2EB8F /* Debug */, 230 | B0053BA61A56B1AE00B2EB8F /* Release */, 231 | ); 232 | defaultConfigurationIsVisible = 0; 233 | defaultConfigurationName = Release; 234 | }; 235 | B0053BA71A56B1AE00B2EB8F /* Build configuration list for PBXNativeTarget "xkbswitch" */ = { 236 | isa = XCConfigurationList; 237 | buildConfigurations = ( 238 | B0053BA81A56B1AE00B2EB8F /* Debug */, 239 | B0053BA91A56B1AE00B2EB8F /* Release */, 240 | ); 241 | defaultConfigurationIsVisible = 0; 242 | defaultConfigurationName = Release; 243 | }; 244 | /* End XCConfigurationList section */ 245 | }; 246 | rootObject = B0053B981A56B1AE00B2EB8F /* Project object */; 247 | } 248 | -------------------------------------------------------------------------------- /xkbswitch/main.m: -------------------------------------------------------------------------------- 1 | // Xkbswitch - console keyboard layout switcher for Mac OS X 2 | // 3 | // The MIT License (MIT) 4 | // 5 | // Copyright (c) 2015 Alexander Myshov 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all 15 | // copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | // SOFTWARE. 24 | 25 | 26 | #import 27 | #import 28 | 29 | 30 | OSStatus set_by_name(const char** argv, const NSString* prefix) { 31 | NSString *macosx_layout_name; 32 | macosx_layout_name = [prefix stringByAppendingString:[NSString stringWithUTF8String:*argv]]; 33 | NSArray* sources = CFBridgingRelease(TISCreateInputSourceList((__bridge CFDictionaryRef)@{ (__bridge NSString*)kTISPropertyInputSourceID : macosx_layout_name}, FALSE)); 34 | TISInputSourceRef source = (__bridge TISInputSourceRef)sources[0]; 35 | OSStatus status = TISSelectInputSource(source); 36 | return status; 37 | } 38 | 39 | int main(int argc, const char * argv[]) { 40 | @autoreleasepool { 41 | NSArray *layouts = [[NSArray alloc] initWithObjects: 42 | @"2SetHangul", 43 | @"390Hangul", 44 | @"3SetHangul", 45 | @"AfghanDari", 46 | @"AfghanPashto", 47 | @"AfghanUzbek", 48 | @"Anjal", 49 | @"Arabic", 50 | @"Arabic-QWERTY", 51 | @"ArabicPC", 52 | @"Armenian-HMQWERTY", 53 | @"Armenian-WesternQWERTY", 54 | @"Australian", 55 | @"Austrian", 56 | @"Azeri", 57 | @"Bangla", 58 | @"Bangla-QWERTY", 59 | @"Belgian", 60 | @"Brazilian", 61 | @"British", 62 | @"British-PC", 63 | @"Bulgarian", 64 | @"Bulgarian-Phonetic", 65 | @"Byelorussian", 66 | @"Canadian", 67 | @"Canadian-CSA", 68 | @"CangjieKeyboard", 69 | @"Cherokee-Nation", 70 | @"Cherokee-QWERTY", 71 | @"Colemak", 72 | @"Croatian", 73 | @"Croatian-PC", 74 | @"Czech", 75 | @"Czech-QWERTY", 76 | @"DVORAK-QWERTYCMD", 77 | @"Danish", 78 | @"Devanagari", 79 | @"Devanagari-QWERTY", 80 | @"Dutch", 81 | @"Dvorak", 82 | @"Dvorak-Left", 83 | @"Dvorak-Right", 84 | @"Estonian", 85 | @"Faroese", 86 | @"Finnish", 87 | @"FinnishExtended", 88 | @"FinnishSami-PC", 89 | @"French", 90 | @"French-numerical", 91 | @"GJCRomaja", 92 | @"Georgian-QWERTY", 93 | @"German", 94 | @"Greek", 95 | @"GreekPolytonic", 96 | @"Gujarati", 97 | @"Gujarati-QWERTY", 98 | @"Gurmukhi", 99 | @"Gurmukhi-QWERTY", 100 | @"HNCRomaja", 101 | @"Hawaiian", 102 | @"Hebrew", 103 | @"Hebrew-PC", 104 | @"Hebrew-QWERTY", 105 | @"Hungarian", 106 | @"Icelandic", 107 | @"Inuktitut-Nunavut", 108 | @"Inuktitut-Nutaaq", 109 | @"Inuktitut-QWERTY", 110 | @"InuttitutNunavik", 111 | @"Irish", 112 | @"IrishExtended", 113 | @"Italian", 114 | @"Italian-Pro", 115 | @"Jawi-QWERTY", 116 | @"KANA", 117 | @"Kannada", 118 | @"Kannada-QWERTY", 119 | @"Kazakh", 120 | @"Khmer", 121 | @"Kurdish-Sorani", 122 | @"Latvian", 123 | @"Lithuanian", 124 | @"Macedonian", 125 | @"Malayalam", 126 | @"Malayalam-QWERTY", 127 | @"Maltese", 128 | @"Maori", 129 | @"Myanmar-QWERTY", 130 | @"Nepali", 131 | @"NorthernSami", 132 | @"Norwegian", 133 | @"NorwegianExtended", 134 | @"NorwegianSami-PC", 135 | @"Oriya", 136 | @"Oriya-QWERTY", 137 | @"Persian", 138 | @"Persian-ISIRI2901", 139 | @"Persian-QWERTY", 140 | @"Polish", 141 | @"PolishPro", 142 | @"Portuguese", 143 | @"Romanian", 144 | @"Romanian-Standard", 145 | @"Russian", 146 | @"Russian-Phonetic", 147 | @"RussianWin", 148 | @"Sami-PC", 149 | @"Serbian", 150 | @"Serbian-Latin", 151 | @"Sinhala", 152 | @"Sinhala-QWERTY", 153 | @"Slovak", 154 | @"Slovak-QWERTY", 155 | @"Slovenian", 156 | @"Spanish", 157 | @"Spanish-ISO", 158 | @"Swedish", 159 | @"Swedish-Pro", 160 | @"SwedishSami-PC", 161 | @"SwissFrench", 162 | @"SwissGerman", 163 | @"Tamil99", 164 | @"Telugu", 165 | @"Telugu-QWERTY", 166 | @"Thai", 167 | @"Thai-PattaChote", 168 | @"Tibetan-QWERTY", 169 | @"Tibetan-Wylie", 170 | @"TibetanOtaniUS", 171 | @"Turkish", 172 | @"Turkish-QWERTY", 173 | @"Turkish-QWERTY-PC", 174 | @"US", 175 | @"USExtended", 176 | @"USInternational-PC", 177 | @"Ukrainian", 178 | @"UnicodeHexInput", 179 | @"Urdu", 180 | @"Uyghur", 181 | @"Vietnamese", 182 | @"Welsh", 183 | @"WubihuaKeyboard", 184 | @"WubixingKeyboard", 185 | @"ZhuyinBopomofo", 186 | @"ZhuyinEten", 187 | nil]; 188 | 189 | int c; 190 | int argc_init = argc; 191 | int layout_by_name = 0; 192 | int layout_by_num = 1; 193 | int set_mode = 0; 194 | int get_mode = 0; 195 | // Get enabled keyboard layouts list 196 | CFArrayRef sourceList = (CFArrayRef) TISCreateInputSourceList (NULL, false); 197 | 198 | while (--argc > 0 && (*++argv)[0] == '-') { 199 | while ((c = *++argv[0])) { 200 | switch (c) { 201 | case 's': 202 | set_mode = 1; 203 | break; 204 | case 'g': 205 | get_mode = 1; 206 | break; 207 | case 'n': 208 | layout_by_num = 1; 209 | break; 210 | case 'e': 211 | layout_by_name = 1; 212 | break; 213 | case 'l': 214 | for (int i = 0; i < [layouts count]; i++) { 215 | printf("%s\n", [layouts[i] UTF8String]); 216 | } 217 | break; 218 | default: 219 | printf("xkbswitch: illegal option %c\n", c); 220 | argc = 0; 221 | break; 222 | } 223 | } 224 | } 225 | 226 | // if there was no options show help 227 | if (argc_init == 1) { 228 | printf("Usage: xkbswitch -g|s [-n|e] [value]\n" 229 | "-g get mode\n" 230 | "-s set mode\n" 231 | "-n setting and getting by numeric mode (default)\n" 232 | "-e setting and getting by string mode\n" 233 | "-l list all available layouts (their names)\n"); 234 | exit(0); 235 | } 236 | 237 | if (get_mode) { 238 | if (layout_by_name) { 239 | // get current keyboard layout by name 240 | TISInputSourceRef current_source = TISCopyCurrentKeyboardInputSource(); 241 | NSString *s = (__bridge NSString *)(TISGetInputSourceProperty(current_source, kTISPropertyInputSourceID)); 242 | // get last part of string (without com.apple.keylayout.) 243 | NSUInteger last_dot_num = [s rangeOfString:@"." options:NSBackwardsSearch].location; 244 | NSString *substring = [s substringFromIndex:last_dot_num + 1]; 245 | printf("%s", [substring UTF8String]); 246 | } else if (layout_by_num) { 247 | // Get current keyborad layout 248 | TISInputSourceRef currentSource = TISCopyCurrentKeyboardInputSource(); 249 | long sourceCount = CFArrayGetCount(sourceList); 250 | 251 | // Search an index of the keyboard layout 252 | for (int i = 0; i < sourceCount; i++) 253 | // If the index is found 254 | if (TISGetInputSourceProperty((TISInputSourceRef) CFArrayGetValueAtIndex(sourceList, i), kTISPropertyLocalizedName) == TISGetInputSourceProperty(currentSource, kTISPropertyLocalizedName)) { 255 | // Print the index 256 | printf("%d", i); 257 | 258 | return 0; 259 | } 260 | } 261 | exit(0); 262 | } else if (set_mode) { 263 | if (layout_by_name) { 264 | OSStatus status = set_by_name(argv, @"com.apple.keylayout."); 265 | if (status != noErr) { 266 | printf("There is no active layout with name in the default prefix \"%s\"\n", *argv); 267 | printf("Trying with the org.unknown.keylayout prefix...\n"); 268 | status = set_by_name(argv, @"org.unknown.keylayout."); 269 | if (status != noErr) { 270 | printf("Unable to find an active layout with this name.\n"); 271 | } 272 | } 273 | } else if (layout_by_num) { 274 | // Get the first argument. It is index of wanted keyboard layout 275 | int wantedSourceIndex = atoi(*argv); 276 | // Get wanted keyboard layout by index 277 | TISInputSourceRef wantedSource = (TISInputSourceRef) CFArrayGetValueAtIndex(sourceList, wantedSourceIndex); 278 | 279 | // If a keyboard layout with the index does not exist 280 | if (!wantedSource) { 281 | printf("%d", -1); 282 | return 1; 283 | } 284 | 285 | // Switch to wanted keyboard layout 286 | TISSelectInputSource(wantedSource); 287 | } 288 | exit(0); 289 | } 290 | 291 | 292 | } 293 | return 0; 294 | } 295 | --------------------------------------------------------------------------------