├── demo.gif ├── MathSymbolsInput ├── Base.lproj │ └── InfoPlist.strings ├── icon.pdf ├── Commands.h ├── InputController.h ├── main.m ├── Info.plist ├── Commands.m ├── commands.txt └── InputController.m ├── MathSymbolsInputPreferences ├── Assets.xcassets │ ├── Contents.json │ └── AppIcon.appiconset │ │ ├── icon_128x128.png │ │ ├── icon_16x16.png │ │ ├── icon_256x256.png │ │ ├── icon_32x32.png │ │ ├── icon_512x512.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_512x512@2x.png │ │ └── Contents.json ├── AboutController.swift ├── TabController.swift ├── Info.plist ├── AppDelegate.swift ├── DefaultCommandsController.swift ├── CustomCommandsController.swift └── Base.lproj │ └── Main.storyboard ├── install.sh ├── uninstall.sh ├── InstallerSections.plist ├── MathSymbolsInput-components.plist ├── MathSymbolsInputPreferences-components.plist ├── distribution.xml ├── LICENSE ├── .gitignore ├── DEVELOPMENT.md ├── package.sh ├── README.md ├── MathSymbolsInput.xcodeproj ├── xcshareddata │ └── xcschemes │ │ ├── activate.xcscheme │ │ ├── MathSymbolsInput.xcscheme │ │ └── MathSymbolsInputPreferences.xcscheme └── project.pbxproj └── activate └── main.m /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/demo.gif -------------------------------------------------------------------------------- /MathSymbolsInput/Base.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | CFBundleName = "Math Symbols Input"; 2 | -------------------------------------------------------------------------------- /MathSymbolsInput/icon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInput/icon.pdf -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /MathSymbolsInput/Commands.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | void loadDefaultCommands(void); 4 | 5 | NSString *findReplacement(NSString *command); 6 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eux 3 | 4 | sudo cp -R "build/Debug/Math Symbols Input.app" "/Library/Input Methods" 5 | killall -9 "Math Symbols Input" 6 | -------------------------------------------------------------------------------- /MathSymbolsInput/InputController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface InputController : IMKInputController 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eux 3 | 4 | sudo rm -rf "/Library/Input Methods/Math Symbols Input.app" 5 | sudo rm -rf "/Applications/Math Symbols Input - Preferences.app" 6 | killall -9 "Math Symbols Input" 7 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/knrafto/MathSymbolsInput/HEAD/MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /InstallerSections.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SectionOrder 6 | 7 | Introduction 8 | Target 9 | PackageSelection 10 | Install 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /MathSymbolsInput-components.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BundleHasStrictIdentifier 7 | 8 | BundleIsRelocatable 9 | 10 | BundleIsVersionChecked 11 | 12 | BundleOverwriteAction 13 | upgrade 14 | RootRelativeBundlePath 15 | Math Symbols Input.app 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences-components.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BundleHasStrictIdentifier 7 | 8 | BundleIsRelocatable 9 | 10 | BundleIsVersionChecked 11 | 12 | BundleOverwriteAction 13 | upgrade 14 | RootRelativeBundlePath 15 | Math Symbols Input - Preferences.app 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/AboutController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Cocoa 3 | 4 | class AboutController : NSViewController { 5 | @IBOutlet weak var versionField: NSTextField! 6 | @IBOutlet weak var copyrightField: NSTextField! 7 | 8 | override func viewDidLoad() { 9 | let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String 10 | if version != nil { 11 | versionField.stringValue = "Version " + version! 12 | } 13 | } 14 | 15 | @IBAction func visitHomepage(_ sender: Any) { 16 | NSWorkspace.shared.open(URL(string: "https://github.com/knrafto/MathSymbolsInput")!) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MathSymbolsInput/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import "Commands.h" 5 | 6 | // Unique connection name for this input method. 7 | static NSString *kConnectionName = @"MathSymbolsInput_1_Connection"; 8 | 9 | int main(int argc, const char *argv[]) { 10 | loadDefaultCommands(); 11 | // Server that accepts connections from client applications. It will create an 12 | // InputController instance to handle each client connection. 13 | IMKServer *server = [[IMKServer alloc] initWithName:kConnectionName bundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]]; 14 | (void) server; 15 | // Run the app. 16 | [[NSApplication sharedApplication] run]; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/TabController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Cocoa 3 | 4 | class TabController : NSTabViewController { 5 | override func viewDidAppear() { 6 | switchSelectedTab() 7 | } 8 | 9 | // Switches tabs depending on what menu item the user clicked to get here 10 | // (communicated through UserDefaults). 11 | func switchSelectedTab() { 12 | let preferences = UserDefaults(suiteName: kSuiteName) 13 | guard let targetTabId = preferences?.string(forKey: kPreferencesTabKey) else { 14 | return 15 | } 16 | for (i, tabViewItem) in tabViewItems.enumerated() { 17 | guard let tabId = tabViewItem.identifier as? String else { 18 | continue 19 | } 20 | if tabId == targetTabId { 21 | selectedTabViewItemIndex = i 22 | break 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Math Symbols Input 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | MathSymbolsInput.pkg 16 | 17 | 18 | 19 | MathSymbolsInputPreferences.pkg 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2023 Kyle Raftogianis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(VERSION) 21 | CFBundleVersion 22 | $(VERSION) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(COPYRIGHT) 27 | NSMainStoryboardFile 28 | Main 29 | NSPrincipalClass 30 | NSApplication 31 | LSUIElement 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | // Bundle identifer of the main input method. 4 | let kSuiteName = "com.mathsymbolsinput.inputmethod.MathSymbolsInput" 5 | // UserDefaults key for default commands. 6 | let kDefaultCommandsKey = "DefaultCommands" 7 | // UserDefaults key for custom commands. 8 | let kCustomCommandsKey = "CustomCommands" 9 | // UserDefaults key for the preferences tab. 10 | let kPreferencesTabKey = "PreferencesTab" 11 | 12 | @NSApplicationMain 13 | class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { 14 | func applicationDidFinishLaunching(_ notification: Notification) { 15 | NSApp.mainWindow?.delegate = self 16 | NSApp.activate(ignoringOtherApps: true) 17 | } 18 | 19 | func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { 20 | // The user clicked a menu item from the input method menu. Update the current tab 21 | // to reflect their choice 22 | let tabController = NSApp.mainWindow?.contentViewController as? TabController 23 | tabController?.switchSelectedTab() 24 | return true 25 | } 26 | 27 | func applicationWillResignActive(_ notification: Notification) { 28 | NSApp.mainWindow?.close() 29 | } 30 | 31 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 32 | return true 33 | } 34 | 35 | func windowWillClose(_ notification: Notification) { 36 | // Ensure any currently-edited command gets saved 37 | NSApp.mainWindow?.makeFirstResponder(NSApp.mainWindow?.initialFirstResponder); 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /MathSymbolsInput/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(VERSION) 25 | InputMethodConnectionName 26 | MathSymbolsInput_1_Connection 27 | InputMethodServerControllerClass 28 | InputController 29 | InputMethodServerDelegateClass 30 | InputController 31 | LSBackgroundOnly 32 | 33 | LSMinimumSystemVersion 34 | $(MACOSX_DEPLOYMENT_TARGET) 35 | NSHumanReadableCopyright 36 | $(COPYRIGHT) 37 | NSPrincipalClass 38 | NSApplication 39 | TISInputSourceID 40 | $(PRODUCT_BUNDLE_IDENTIFIER) 41 | tsInputMethodIconFileKey 42 | icon.pdf 43 | 44 | 45 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | *.pkg 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | project.xcworkspace/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xccheckout 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | # CocoaPods 34 | # 35 | # We recommend against adding the Pods directory to your .gitignore. However 36 | # you should judge for yourself, the pros and cons are mentioned at: 37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 38 | # 39 | # Pods/ 40 | # 41 | # Add this line if you want to avoid checking in source code from the Xcode workspace 42 | # *.xcworkspace 43 | 44 | # Carthage 45 | # 46 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 47 | # Carthage/Checkouts 48 | 49 | Carthage/Build 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 54 | # screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 57 | 58 | fastlane/report.xml 59 | fastlane/Preview.html 60 | fastlane/screenshots/**/*.png 61 | fastlane/test_output 62 | 63 | # Code Injection 64 | # 65 | # After new code Injection tools there's a generated folder /iOSInjectionProject 66 | # https://github.com/johnno1962/injectionforxcode 67 | 68 | iOSInjectionProject/ 69 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/DefaultCommandsController.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Cocoa 3 | 4 | class DefaultCommandsController : NSViewController, NSTableViewDataSource, NSTableViewDelegate { 5 | @IBOutlet weak var tableView: NSTableView! 6 | // Table contents, as a list of (column id -> value) dictionaries. 7 | var contents: [[String: String]] = [] 8 | var filteredContents: [[String: String]] = [] 9 | 10 | override func viewDidLoad() { 11 | super.viewDidLoad() 12 | 13 | let preferences = UserDefaults(suiteName: kSuiteName) 14 | let defaultCommands = preferences?.dictionary(forKey: kDefaultCommandsKey) ?? [:] 15 | for command in Array(defaultCommands.keys).sorted() { 16 | guard let replacement = defaultCommands[command] as? String else { 17 | continue 18 | } 19 | contents.append([ 20 | "command": command, 21 | "replacement": replacement, 22 | ]) 23 | } 24 | filteredContents = contents 25 | tableView.reloadData() 26 | 27 | // Work around macOS bug where the header obscures the first row 28 | if (tableView.numberOfRows > 0) { 29 | tableView.scrollRowToVisible(0) 30 | } 31 | } 32 | 33 | // For NSTableViewDataSource. 34 | func numberOfRows(in tableView: NSTableView) -> Int { 35 | return filteredContents.count 36 | } 37 | 38 | // For NSTableViewDelegate. 39 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 40 | let view = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self) as! NSTableCellView 41 | view.textField?.stringValue = filteredContents[row][tableColumn!.identifier.rawValue]! 42 | return view 43 | } 44 | 45 | // Called when the user types in a search. 46 | @IBAction func search(_ sender: NSSearchField) { 47 | let searchText = sender.stringValue.trimmingCharacters(in: .whitespacesAndNewlines) 48 | if searchText.isEmpty { 49 | filteredContents = contents 50 | } else { 51 | filteredContents = contents.filter { 52 | return $0["command"]!.contains(searchText) || $0["replacement"]!.contains(searchText) 53 | } 54 | } 55 | tableView.reloadData() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | The project has the following targets: 4 | * MathSymbolsInput: the core input method, installed in `/Library/Input Methods` 5 | * MathSymbolsInputPreferences: a GUI app for the "Preferences..." menu, installed in 6 | `/Applications` 7 | * activate: a command-line tool to enable and select the input method after an install 8 | or upgrade 9 | 10 | These are configured to build into the `build/` directory. The preferences app 11 | can be run normally from Xcode during development. The others require a bit more 12 | work to test. 13 | 14 | ## Testing the input method 15 | 16 | To update the input method with your local debug build, first switch to a 17 | different input method, run `./install.sh`, and switch back. To view 18 | `NSLog` output, open Console.app and search for "Math Symbols Input". 19 | 20 | ## Testing the installer 21 | 22 | Run `./package` to create a release build and package it into a `.pkg` 23 | file for the macOS installer. Run `open MathSymbolsInput.pkg` to perform an install. 24 | 25 | ## Reference documentation 26 | 27 | * Carbon header file: https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.6.sdk/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/TextInputSources.h 28 | * Apple tech note on input methods: http://mirror.informatimago.com/next/developer.apple.com/technotes/tn2005/tn2128.html 29 | * InputMethodKit documentation: https://developer.apple.com/documentation/inputmethodkit 30 | * Cocoa text editing overview: https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TextEditing/TextEditing.html 31 | 32 | ## Text format 33 | 34 | The text format is a line-oriented UTF-8 text file, with lines ending in either `\r\n` or `\n`. Each line is either: 35 | 36 | * Empty 37 | * A comment line, beginning with `#` 38 | * A command and a replacement, separated by a single space. 39 | 40 | Commands: 41 | * must start with `\` 42 | * cannot contain space, `\r`, or `\n` characters 43 | * are at most 1000 Unicode code points long. 44 | 45 | Replacements: 46 | * cannot contain `\r` or `\n` characters (but they can contain space characters) 47 | * are at most 1000 Unicode code points long. 48 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Creates an installer package for distribution. Before running, create an 4 | # "app-specific password" for notarytool and store it in the keychain: 5 | # 6 | # xcrun notarytool store-credentials "AC_PASSWORD" --apple-id --team-id --password 7 | 8 | if [[ $# -ne 1 ]] ; then 9 | echo 'usage: ./package.sh IDENTITY' 10 | echo 'e.g. ./package.sh "John Doe (12345ABCDE)"' 11 | exit 1 12 | fi 13 | IDENTITY=$1 14 | CODESIGN_FLAGS="-v --force --timestamp --options=runtime" 15 | 16 | set -eux 17 | 18 | xcodebuild -alltargets -configuration Release 19 | 20 | # Order matters when signing: .app bundles must be signed last. 21 | codesign $CODESIGN_FLAGS --sign "Developer ID Application: $IDENTITY" "build/Release/Math Symbols Input.app/Contents/MacOS/Math Symbols Input" 22 | find "build/Release/Math Symbols Input.app" -name "*.dylib" -exec codesign $CODESIGN_FLAGS --sign "Developer ID Application: $IDENTITY" {} \; 23 | codesign $CODESIGN_FLAGS --sign "Developer ID Application: $IDENTITY" "build/Release/Math Symbols Input.app" 24 | 25 | codesign $CODESIGN_FLAGS --sign "Developer ID Application: $IDENTITY" "build/Release/Math Symbols Input - Preferences.app/Contents/MacOS/Math Symbols Input - Preferences" 26 | find "build/Release/Math Symbols Input - Preferences.app" -name "*.dylib" -exec codesign $CODESIGN_FLAGS --sign "Developer ID Application: $IDENTITY" {} \; 27 | codesign $CODESIGN_FLAGS --sign "Developer ID Application: $IDENTITY" "build/Release/Math Symbols Input - Preferences.app" 28 | 29 | codesign $CODESIGN_FLAGS --sign "Developer ID Application: $IDENTITY" build/Release/activate 30 | 31 | mkdir -p build/Root/MathSymbolsInput 32 | cp -R "build/Release/Math Symbols Input.app" build/Root/MathSymbolsInput 33 | 34 | mkdir -p build/Root/MathSymbolsInputPreferences 35 | cp -R "build/Release/Math Symbols Input - Preferences.app" build/Root/MathSymbolsInputPreferences 36 | 37 | mkdir -p build/Root/Scripts 38 | cp build/Release/activate build/Root/Scripts/activate 39 | cat > build/Root/Scripts/postinstall <<'EOF' 40 | #!/bin/bash 41 | LOGIN_USER=$(/usr/bin/stat -f%Su /dev/console) 42 | /usr/bin/sudo -u "$LOGIN_USER" ./activate 43 | EOF 44 | chmod +x build/Root/Scripts/postinstall 45 | 46 | mkdir -p build/Package 47 | pkgbuild \ 48 | --root build/Root/MathSymbolsInput \ 49 | --component-plist MathSymbolsInput-components.plist \ 50 | --install-location "/Library/Input Methods" \ 51 | --scripts build/Root/Scripts \ 52 | build/Package/MathSymbolsInput.pkg 53 | pkgbuild \ 54 | --root build/Root/MathSymbolsInputPreferences \ 55 | --component-plist MathSymbolsInputPreferences-components.plist \ 56 | --install-location /Applications \ 57 | build/Package/MathSymbolsInputPreferences.pkg 58 | productbuild \ 59 | --distribution distribution.xml \ 60 | --package-path build/Package \ 61 | --sign "Developer ID Installer: $IDENTITY" \ 62 | MathSymbolsInput.pkg 63 | 64 | xcrun notarytool submit MathSymbolsInput.pkg --keychain-profile "AC_PASSWORD" --wait 65 | xcrun stapler staple MathSymbolsInput.pkg 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Math Symbols Input** is a macOS [input method](https://en.wikipedia.org/wiki/Input_method) for typing mathematical symbols with LaTeX-style commands. 2 | It works seamlessly with any Mac app. 3 | 4 | ![Math Symbols Input Demo](demo.gif) 5 | 6 | # Installation 7 | 8 | The latest version is Version 1.3. To install or update Math Symbols Input: 9 | 10 | 1. Download the [installer for the latest version](https://github.com/knrafto/MathSymbolsInput/releases/latest/download/MathSymbolsInput.pkg). 11 | 2. Open the installer and continue through the installation steps. 12 | 3. Log out and log back in (or reboot). 13 | 14 | The installer can enable the input method automatically. If you want to configure input sources, see the [macOS help page on input sources]( 15 | https://support.apple.com/guide/mac-help/type-language-mac-input-sources-mchlp1406/mac). 16 | 17 | # Usage 18 | 19 | Type a backslash `\` to start a command. The text should appear underlined while the command is being typed to show the input method is active. While the input method is active: 20 | 21 | * Typing normally by pressing letters, symbols, or the backspace key will edit the command. 22 | * **Enter** or **tab** will replace the command with its math symbol. If the command does not have an associated math symbol, the command text will be inserted verbatim instead. 23 | * **Space** will replace the command and insert a space afterward. 24 | * **Backslash** will replace the command and start a new command. 25 | * **Escape** will insert the command text verbatim (e.g. if you need to type `\alpha` instead of `α`). 26 | 27 | ## Default commands 28 | 29 | To view a searchable list of all default commands, click the Math Input Symbols `∀` icon in the menu bar and select `View Default Commands...`. 30 | The default commands are also listed in [this text file](https://github.com/knrafto/MathSymbolsInput/blob/master/MathSymbolsInput/commands.txt). 31 | 32 | If you think some command would be broadly usable and should be a default command, consider opening an issue or pull request. 33 | 34 | ## Custom commands 35 | 36 | To add your own commands, click the Math Input Symbols `∀` icon in the menu bar and select `Edit Custom Commands...`. 37 | New commands will take effect immediately. 38 | 39 | # FAQ 40 | 41 | ## Are there Windows or Linux versions? 42 | 43 | Not yet, but hopefully soon. 44 | 45 | ## Can I use a keyboard layout other than the US layout? 46 | 47 | Yes, Math Symbols Input uses the last selected keyboard layout. [Dead keys](https://en.wikipedia.org/wiki/Dead_key) 48 | will continue to work, but the macOS's press-and-hold [accent menu](https://support.apple.com/guide/mac-help/enter-characters-with-accent-marks-on-mac-mh27474/mac) 49 | unfortunately will not. 50 | 51 | # Inspirations 52 | 53 | Many programming languages are capable of inputting mathematical symbols, but this is usually limited to a single app. These include: 54 | 55 | * [Agda](https://agda.readthedocs.io/en/latest/tools/emacs-mode.html#unicode-input) 56 | * [Julia](https://docs.julialang.org/en/v1/manual/unicode-input/) 57 | * [Lean](https://leanprover.github.io/reference/using_lean.html#features) 58 | -------------------------------------------------------------------------------- /MathSymbolsInput/Commands.m: -------------------------------------------------------------------------------- 1 | #include "Commands.h" 2 | 3 | #import 4 | 5 | // .txt file containing default commands. 6 | static NSString *kDefaultCommandsResourceName = @"commands"; 7 | // NSUserDefaults key for default commands. 8 | static NSString *kDefaultCommandsKey = @"DefaultCommands"; 9 | // NSUserDefaults key for custom commands. 10 | static NSString *kCustomCommandsKey = @"CustomCommands"; 11 | 12 | // Map from NSString* commands NSString* replacements. 13 | static NSMutableDictionary *defaultCommands = nil; 14 | 15 | void loadDefaultCommands(void) { 16 | defaultCommands = [[NSMutableDictionary alloc] init]; 17 | NSBundle *bundle = [NSBundle mainBundle]; 18 | NSString *path = [bundle pathForResource:kDefaultCommandsResourceName ofType:@"txt"]; 19 | if (path == nil) { 20 | NSLog(@"No file %@.txt in %@", kDefaultCommandsResourceName, [bundle resourcePath]); 21 | return; 22 | } 23 | NSLog(@"Loading commands from %@", path); 24 | 25 | NSError *error = nil; 26 | NSString *contents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; 27 | if (contents == nil) { 28 | NSLog(@"Could not read %@: %@", path, [error localizedDescription]); 29 | return; 30 | } 31 | 32 | int errors = 0; 33 | int lineNumber = 0; 34 | // TODO: handle \r\n line endings. 35 | for (NSString *line in [contents componentsSeparatedByString:@"\n"]) { 36 | lineNumber++; 37 | // Blank or comment line. 38 | if ([line length] == 0 || [line hasPrefix:@"#"]) { 39 | continue; 40 | } 41 | 42 | NSUInteger i = [line rangeOfString:@" "].location; 43 | if (i == NSNotFound) { 44 | NSLog(@"Syntax error on line %d: expected command and replacement separated by a space", lineNumber); 45 | errors++; 46 | continue; 47 | } 48 | 49 | // TODO: validate command and replacement. 50 | NSString *command = [line substringToIndex:i]; 51 | NSString *replacement = [line substringFromIndex:(i + 1)]; 52 | 53 | if (![line hasPrefix:@"\\"]) { 54 | NSLog(@"Syntax error on line %d: command must start with a backslash", lineNumber); 55 | errors++; 56 | continue; 57 | } 58 | 59 | if (defaultCommands[command] != nil) { 60 | NSLog(@"Error on line %d: command '%@' already defined", lineNumber, command); 61 | errors++; 62 | continue; 63 | } 64 | 65 | [defaultCommands setObject:replacement forKey:command]; 66 | } 67 | 68 | // Save commands to UserDefaults so the preferences app can read them easily. 69 | [[NSUserDefaults standardUserDefaults] setObject:defaultCommands forKey:kDefaultCommandsKey]; 70 | 71 | NSLog(@"Loaded %lu default commands with %d errors", (unsigned long)[defaultCommands count], errors); 72 | } 73 | 74 | NSString *findReplacement(NSString *command) { 75 | NSDictionary *customCommands = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kCustomCommandsKey]; 76 | if (customCommands != nil) { 77 | id replacement = customCommands[command]; 78 | if (replacement != nil && [replacement isKindOfClass:[NSString class]]) { 79 | return replacement; 80 | } 81 | } 82 | 83 | return defaultCommands[command]; 84 | } 85 | -------------------------------------------------------------------------------- /MathSymbolsInput.xcodeproj/xcshareddata/xcschemes/activate.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /activate/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | static const char *kInstallLocation = "/Library/Input Methods/Math Symbols Input.app"; 4 | static NSString *kProcessName = @"Math Symbols Input"; 5 | static NSString *kSourceID = @"com.mathsymbolsinput.inputmethod.MathSymbolsInput"; 6 | 7 | static void logIfError(OSStatus status, NSString *message) { 8 | if (status != noErr) { 9 | NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; 10 | NSLog(@"%@: %@", message, [error localizedDescription]); 11 | } 12 | } 13 | 14 | // Enables and selects the input method after an install or upgrade. 15 | // 16 | // We sleep for a bit between steps because it seems like many things happen in 17 | // the background, and if we do some steps too quickly then things could be 18 | // left in an inconsistent state. 19 | int main(int argc, const char *argv[]) { 20 | @autoreleasepool { 21 | 22 | // Running as root won't actually activate the input method and seems to 23 | // leave things broken until the next reboot. 24 | if (geteuid() == 0) { 25 | NSLog(@"Activate script should not be run as root, aborting"); 26 | return 1; 27 | } 28 | 29 | CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *) kInstallLocation, strlen(kInstallLocation), NO); 30 | NSLog(@"Registering input source %s", kInstallLocation); 31 | logIfError(TISRegisterInputSource(url), @"Could not register input source"); 32 | CFRelease(url); 33 | [NSThread sleepForTimeInterval:1.0]; 34 | 35 | // Find our input method. 36 | TISInputSourceRef inputMethod = nil; 37 | CFArrayRef inputSources = TISCreateInputSourceList(NULL, YES); 38 | for (int i = 0; i < CFArrayGetCount(inputSources); i++) { 39 | TISInputSourceRef inputSource = (TISInputSourceRef) CFArrayGetValueAtIndex(inputSources, i); 40 | NSString *sourceID = (__bridge NSString *) TISGetInputSourceProperty(inputSource, kTISPropertyInputSourceID); 41 | if ([sourceID isEqualToString:kSourceID]) { 42 | inputMethod = inputSource; 43 | break; 44 | } 45 | } 46 | if (inputMethod == nil) { 47 | NSLog(@"Could not find input source %@", kSourceID); 48 | return 1; 49 | } 50 | 51 | // We shouldn't kill an input method while it's active, so we disable it first. 52 | if (CFBooleanGetValue(TISGetInputSourceProperty(inputMethod, kTISPropertyInputSourceIsEnabled))) { 53 | NSLog(@"Disabling input source %@", kSourceID); 54 | logIfError(TISDisableInputSource(inputMethod), @"Could not disable input source"); 55 | [NSThread sleepForTimeInterval:1.0]; 56 | } 57 | 58 | // We have to kill the old process for the new version to take effect. The 59 | // new process will be started automatically. 60 | NSLog(@"Killing process %@", kProcessName); 61 | NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/killall" arguments:@[kProcessName]]; 62 | [task waitUntilExit]; 63 | [NSThread sleepForTimeInterval:1.0]; 64 | 65 | NSLog(@"Enabling input source %@", kSourceID); 66 | logIfError(TISEnableInputSource(inputMethod), @"Could not enable input source"); 67 | [NSThread sleepForTimeInterval:1.0]; 68 | 69 | NSLog(@"Selecting input source %@", kSourceID); 70 | logIfError(TISSelectInputSource(inputMethod), @"Could not select input source"); 71 | 72 | CFRelease(inputSources); 73 | } 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /MathSymbolsInput.xcodeproj/xcshareddata/xcschemes/MathSymbolsInput.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /MathSymbolsInput.xcodeproj/xcshareddata/xcschemes/MathSymbolsInputPreferences.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/CustomCommandsController.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | let kMaxStringLength = 1000 4 | 5 | func isValidCommandCharacter(_ c: Character) -> Bool { 6 | return c != " " && c != "\r" && c != "\n" && c != "\r\n" 7 | } 8 | 9 | func isValidReplacementCharacter(_ c: Character) -> Bool { 10 | return c != "\r" && c != "\n" && c != "\r\n" 11 | } 12 | 13 | class CustomCommandsController: NSViewController, NSTableViewDataSource, NSTableViewDelegate { 14 | @IBOutlet weak var tableView: NSTableView! 15 | var preferences: UserDefaults? 16 | // Table contents, as a list of (column id -> value) dictionaries. 17 | var contents: [[String: String]] = [] 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | 22 | preferences = UserDefaults(suiteName: kSuiteName) 23 | let customCommands = preferences?.dictionary(forKey: kCustomCommandsKey) ?? [:] 24 | for command in Array(customCommands.keys).sorted() { 25 | guard let replacement = customCommands[command] as? String else { 26 | continue 27 | } 28 | contents.append([ 29 | "command": command, 30 | "replacement": replacement, 31 | ]) 32 | } 33 | tableView.reloadData() 34 | 35 | // Work around macOS bug where the header obscures the first row 36 | if (tableView.numberOfRows > 0) { 37 | tableView.scrollRowToVisible(0) 38 | } 39 | } 40 | 41 | // Saves the current state to preferences. 42 | func savePreferences() { 43 | var customCommands: [String : String] = [:] 44 | for rowDict in contents { 45 | customCommands[rowDict["command"]!] = rowDict["replacement"]! 46 | } 47 | preferences?.set(customCommands, forKey: kCustomCommandsKey) 48 | } 49 | 50 | // For NSTableViewDataSource. 51 | func numberOfRows(in tableView: NSTableView) -> Int { 52 | return contents.count 53 | } 54 | 55 | // For NSTableViewDelegate. 56 | func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { 57 | let view = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self) as! NSTableCellView 58 | view.textField?.stringValue = contents[row][tableColumn!.identifier.rawValue]! 59 | return view 60 | } 61 | 62 | func addItem() { 63 | // End any current editing. 64 | tableView.window?.makeFirstResponder(nil) 65 | 66 | // Add a new row. 67 | contents.append([ 68 | "command": "\\", 69 | "replacement": "", 70 | ]) 71 | tableView.reloadData() 72 | 73 | // Automatically select and edit the new item. 74 | let newRow = contents.count - 1 75 | tableView.selectRowIndexes(IndexSet(integer: newRow), byExtendingSelection: false) 76 | let view = tableView.view(atColumn: 0, row: newRow, makeIfNecessary: true) as! NSTableCellView 77 | view.textField?.becomeFirstResponder() 78 | let range = view.textField?.currentEditor()?.selectedRange 79 | view.textField?.currentEditor()?.selectedRange = NSMakeRange(range?.length ?? 0, 0) 80 | 81 | // Ensure new row is visible. 82 | tableView.scrollRowToVisible(newRow) 83 | } 84 | 85 | func removeItem() { 86 | // Remove indices in reverse order so items don't move around while we remove them. 87 | for i in tableView.selectedRowIndexes.sorted(by: >) { 88 | contents.remove(at: i) 89 | } 90 | 91 | tableView.reloadData() 92 | savePreferences() 93 | } 94 | 95 | // Called when a table cell is edited. 96 | @IBAction func doneEditing(_ sender: NSTextField) { 97 | let row = tableView.row(for: sender.superview!) 98 | if row == -1 { 99 | return 100 | } 101 | let column = sender.superview!.identifier!.rawValue 102 | 103 | // Make sure the text is valid. 104 | // Technically we trim by extended grapheme clusters instead of code points, but whatever. 105 | var text = sender.stringValue 106 | if column == "command" { 107 | text = text.filter(isValidCommandCharacter) 108 | if text.isEmpty || text.first! != "\\" { 109 | text = "\\" + text 110 | } 111 | text = String(text.prefix(kMaxStringLength)) 112 | } else if column == "replacement" { 113 | text = text.filter(isValidReplacementCharacter) 114 | text = String(text.prefix(kMaxStringLength)) 115 | } 116 | sender.stringValue = text 117 | contents[row][column] = text 118 | savePreferences() 119 | } 120 | 121 | // Called when a +/- button is clicked. 122 | @IBAction func buttonClicked(_ sender: NSSegmentedControl) { 123 | if sender.selectedSegment == 0 { 124 | addItem() 125 | } else if sender.selectedSegment == 1 { 126 | removeItem() 127 | } 128 | } 129 | 130 | // Called when the table is double-clicked. 131 | @IBAction func doubleClicked(_ sender: Any) { 132 | if tableView.clickedRow == -1 && tableView.clickedColumn == -1 { 133 | // The user clicked outside a row. 134 | addItem() 135 | } else if tableView.clickedRow != -1 && tableView.clickedColumn != -1 { 136 | // The user double-clicked a row. Edit the cell. 137 | let view = tableView.view(atColumn: tableView.clickedColumn, row: tableView.clickedRow, makeIfNecessary: true) as! NSTableCellView 138 | view.textField?.becomeFirstResponder() 139 | } 140 | } 141 | } 142 | 143 | -------------------------------------------------------------------------------- /MathSymbolsInput/commands.txt: -------------------------------------------------------------------------------- 1 | # Each line contains an command (starting with \) and its replacement, separated by a space. 2 | # Blank lines and lines starting with '#' are ignored. 3 | 4 | ### Mathematical symbols ### 5 | 6 | # Arrows 7 | \rightarrow → 8 | \to → 9 | \-> → 10 | \hookrightarrow ↪ 11 | \inj ↪ 12 | \leftarrow ← 13 | \<- ← 14 | \leftrightarrow ↔ 15 | \<-> ↔ 16 | \uparrow ↑ 17 | \downarrow ↓ 18 | \Leftrightarrow ⇔ 19 | \<=> ⇔ 20 | \Rightarrow ⇒ 21 | \=> ⇒ 22 | \Leftarrow ⇐ 23 | \Longrightarrow ⟹ 24 | \implies ⟹ 25 | \Longleftarrow ⟸ 26 | \impliedby ⟸ 27 | \Longleftrightarrow ⟺ 28 | \<==> ⟺ 29 | \iff ⟺ 30 | \mapsto ↦ 31 | \|-> ↦ 32 | 33 | # Equality 34 | \ne ≠ 35 | \neq ≠ 36 | \approx ≈ 37 | \~~ ≈ 38 | \equiv ≡ 39 | \== ≡ 40 | \simeq ≃ 41 | \iso ≃ 42 | \~- ≃ 43 | \cong ≅ 44 | \~= ≅ 45 | \=? ≟ 46 | \propto ∝ 47 | 48 | # Order 49 | \leq ≤ 50 | \le ≤ 51 | \<= ≤ 52 | \geq ≥ 53 | \ge ≥ 54 | \>= ≥ 55 | \ll ≪ 56 | \<< ≪ 57 | \gg ≫ 58 | \>> ≫ 59 | \subset ⊂ 60 | \supset ⊃ 61 | \subseteq ⊆ 62 | \supseteq ⊇ 63 | \sqsubset ⊏ 64 | \sqsupset ⊐ 65 | \sqsubseteq ⊑ 66 | \sqsupseteq ⊒ 67 | \prec ≺ 68 | \preceq ≼ 69 | \succ ≻ 70 | \succeq ≽ 71 | \triangleleft ⊲ 72 | \<| ⊲ 73 | \triangleright ⊳ 74 | \|> ⊳ 75 | \trianglelefteq ⊴ 76 | \<|= ⊴ 77 | \trianglerighteq ⊵ 78 | \|>= ⊵ 79 | 80 | # Sets and logic 81 | \neg ¬ 82 | \in ∈ 83 | \notin ∉ 84 | \ni ∋ 85 | \top ⊤ 86 | \bot ⊥ 87 | \forall ∀ 88 | \all ∀ 89 | \exists ∃ 90 | \ex ∃ 91 | \vdash ⊢ 92 | \|- ⊢ 93 | \dashv ⊣ 94 | \-| ⊣ 95 | \vDash ⊨ 96 | \|= ⊨ 97 | \varnothing ∅ 98 | \emptyset ∅ 99 | \aleph ℵ 100 | \beth ℶ 101 | \therefore ∴ 102 | \because ∵ 103 | \qed ∎ 104 | \lightning ↯ 105 | 106 | # Numbers and calculus 107 | \int ∫ 108 | \oint ∮ 109 | \partial ∂ 110 | \del ∇ 111 | \nabla ∇ 112 | \infty ∞ 113 | \inf ∞ 114 | \pm ± 115 | \mp ∓ 116 | \lfloor ⌊ 117 | \rfloor ⌋ 118 | \lceil ⌈ 119 | \rceil ⌉ 120 | 121 | # Operators 122 | \times × 123 | \x × 124 | \div ÷ 125 | \circ ∘ 126 | \o ∘ 127 | \bullet ∙ 128 | \. ∙ 129 | \cdot ⋅ 130 | \Colon ∷ 131 | \:: ∷ 132 | \cup ∪ 133 | \union ∪ 134 | \u ∪ 135 | \cap ∩ 136 | \intersection ∩ 137 | \uplus ⊎ 138 | \u+ ⊎ 139 | \setminus ∖ 140 | \sqcup ⊔ 141 | \sqcap ⊓ 142 | \surd √ 143 | \sqrt √ 144 | \oplus ⊕ 145 | \o+ ⊕ 146 | \ominus ⊖ 147 | \o- ⊖ 148 | \otimes ⊗ 149 | \ox ⊗ 150 | \odot ⊙ 151 | \o. ⊙ 152 | \wr ≀ 153 | \wedge ∧ 154 | \and ∧ 155 | \land ∧ 156 | \vee ∨ 157 | \or ∨ 158 | \lor ∨ 159 | \v ∨ 160 | \veebar ⊻ 161 | \Box □ 162 | \box □ 163 | \ltimes ⋉ 164 | \rtimes ⋊ 165 | \bowtie ⋈ 166 | \coprod ∐ 167 | 168 | # Brackets 169 | \langle ⟨ 170 | \< ⟨ 171 | \rangle ⟩ 172 | \> ⟩ 173 | \Vert ‖ 174 | \|| ‖ 175 | \ulcorner ⌜ 176 | \urcorner ⌝ 177 | \llcorner ⌞ 178 | \lrcorner ⌟ 179 | 180 | # Misc 181 | \ell ℓ 182 | \deg ° 183 | \degree ° 184 | \checkmark ✓ 185 | 186 | ### Typographic symbols ### 187 | 188 | \S § 189 | \P ¶ 190 | \ldots … 191 | \... … 192 | \vdots ⋮ 193 | \cdots ⋯ 194 | \adots ⋰ 195 | \ddots ⋱ 196 | \dagger † 197 | \ddagger ‡ 198 | \copyright © 199 | \(c) © 200 | \registered ® 201 | \(r) ® 202 | \trademark ™ 203 | \tm ™ 204 | 205 | ### Music ### 206 | \sharp ♯ 207 | \# ♯ 208 | \flat ♭ 209 | \b ♭ 210 | \natural ♮ 211 | 212 | ### Superscripts and subscripts ### 213 | # Not all letters are available in Unicode, and the ones that are there often 214 | # come from different ranges and are rendered inconsistently in most fonts. 215 | 216 | \^0 ⁰ 217 | \^1 ¹ 218 | \^2 ² 219 | \^3 ³ 220 | \^4 ⁴ 221 | \^5 ⁵ 222 | \^6 ⁶ 223 | \^7 ⁷ 224 | \^8 ⁸ 225 | \^9 ⁹ 226 | \^+ ⁺ 227 | \^- ⁻ 228 | \^= ⁼ 229 | \^( ⁽ 230 | \^) ⁾ 231 | 232 | \^A ᴬ 233 | \^B ᴮ 234 | \^D ᴰ 235 | \^E ᴱ 236 | \^G ᴳ 237 | \^H ᴴ 238 | \^I ᴵ 239 | \^J ᴶ 240 | \^K ᴷ 241 | \^L ᴸ 242 | \^M ᴹ 243 | \^N ᴺ 244 | \^O ᴼ 245 | \^P ᴾ 246 | \^R ᴿ 247 | \^T ᵀ 248 | \^U ᵁ 249 | \^V ⱽ 250 | \^W ᵂ 251 | 252 | \^a ᵃ 253 | \^b ᵇ 254 | \^c ᶜ 255 | \^d ᵈ 256 | \^e ᵉ 257 | \^f ᶠ 258 | \^g ᵍ 259 | \^h ʰ 260 | \^i ⁱ 261 | \^j ʲ 262 | \^k ᵏ 263 | \^l ˡ 264 | \^m ᵐ 265 | \^n ⁿ 266 | \^o ᵒ 267 | \^p ᵖ 268 | \^r ʳ 269 | \^s ˢ 270 | \^t ᵗ 271 | \^u ᵘ 272 | \^v ᵛ 273 | \^w ʷ 274 | \^x ˣ 275 | \^y ʸ 276 | \^z ᶻ 277 | 278 | \_0 ₀ 279 | \_1 ₁ 280 | \_2 ₂ 281 | \_3 ₃ 282 | \_4 ₄ 283 | \_5 ₅ 284 | \_6 ₆ 285 | \_7 ₇ 286 | \_8 ₈ 287 | \_9 ₉ 288 | \_+ ₊ 289 | \_- ₋ 290 | \_= ₌ 291 | \_( ₍ 292 | \_) ₎ 293 | 294 | \_a ₐ 295 | \_e ₑ 296 | \_h ₕ 297 | \_i ᵢ 298 | \_j ⱼ 299 | \_k ₖ 300 | \_l ₗ 301 | \_m ₘ 302 | \_n ₙ 303 | \_o ₒ 304 | \_p ₚ 305 | \_r ᵣ 306 | \_s ₛ 307 | \_t ₜ 308 | \_u ᵤ 309 | \_v ᵥ 310 | \_x ₓ 311 | 312 | ### Greek letters ### 313 | # Letters that look like a Latin character are omitted. 314 | 315 | \Gamma Γ 316 | \Delta Δ 317 | \Theta Θ 318 | \Lambda Λ 319 | \Xi Ξ 320 | \Pi Π 321 | \Sigma Σ 322 | \Phi Φ 323 | \Psi Ψ 324 | \Omega Ω 325 | \alpha α 326 | \beta β 327 | \gamma γ 328 | \delta δ 329 | # \varepsilon in LaTeX 330 | \epsilon ε 331 | \zeta ζ 332 | \eta η 333 | \theta θ 334 | \iota ι 335 | \kappa κ 336 | \lambda λ 337 | \mu μ 338 | \nu ν 339 | \xi ξ 340 | \pi π 341 | \rho ρ 342 | \varsigma ς 343 | \sigma σ 344 | \tau τ 345 | \upsilon υ 346 | \phi φ 347 | \chi χ 348 | \psi ψ 349 | \omega ω 350 | 351 | ### Shorthand Greek letters ### 352 | 353 | \GG Γ 354 | \GD Δ 355 | \GTH Θ 356 | \GL Λ 357 | \GX Ξ 358 | # \Pi 359 | \GS Σ 360 | \GF Φ 361 | \GP Ψ 362 | \GO Ω 363 | \Ga α 364 | \Gb β 365 | \Gg γ 366 | \Gd δ 367 | \Ge ε 368 | \Gz ζ 369 | \Gh η 370 | \Gth θ 371 | \Gi ι 372 | \Gk κ 373 | \Gl λ 374 | \Gm μ 375 | \Gn ν 376 | \Gx ξ 377 | # \pi 378 | \Gr ρ 379 | # \varsigma 380 | \Gs σ 381 | \Gt τ 382 | \Gu υ 383 | \Gf φ 384 | \Gc χ 385 | \Gp ψ 386 | \Go ω 387 | 388 | ### Blackboard bold ### 389 | 390 | \bA 𝔸 391 | \bB 𝔹 392 | \bC ℂ 393 | \bD 𝔻 394 | \bE 𝔼 395 | \bF 𝔽 396 | \bG 𝔾 397 | \bH ℍ 398 | \bI 𝕀 399 | \bJ 𝕁 400 | \bK 𝕂 401 | \bL 𝕃 402 | \bM 𝕄 403 | \bN ℕ 404 | \bO 𝕆 405 | \bP ℙ 406 | \bQ ℚ 407 | \bR ℝ 408 | \bS 𝕊 409 | \bT 𝕋 410 | \bU 𝕌 411 | \bV 𝕍 412 | \bW 𝕎 413 | \bX 𝕏 414 | \bY 𝕐 415 | \bZ ℤ 416 | \ba 𝕒 417 | \bb 𝕓 418 | \bc 𝕔 419 | \bd 𝕕 420 | \be 𝕖 421 | \bf 𝕗 422 | \bg 𝕘 423 | \bh 𝕙 424 | \bi 𝕚 425 | \bj 𝕛 426 | \bk 𝕜 427 | \bl 𝕝 428 | \bm 𝕞 429 | \bn 𝕟 430 | \bo 𝕠 431 | \bp 𝕡 432 | \bq 𝕢 433 | \br 𝕣 434 | \bs 𝕤 435 | \bt 𝕥 436 | \bu 𝕦 437 | \bv 𝕧 438 | \bw 𝕨 439 | \bx 𝕩 440 | \by 𝕪 441 | \bz 𝕫 442 | \b0 𝟘 443 | \b1 𝟙 444 | \b2 𝟚 445 | \b3 𝟛 446 | \b4 𝟜 447 | \b5 𝟝 448 | \b6 𝟞 449 | \b7 𝟟 450 | \b8 𝟠 451 | \b9 𝟡 452 | 453 | ### Mathematical bold ### 454 | 455 | \B0 𝟎 456 | \B1 𝟏 457 | \B2 𝟐 458 | \B3 𝟑 459 | \B4 𝟒 460 | \B5 𝟓 461 | \B6 𝟔 462 | \B7 𝟕 463 | \B8 𝟖 464 | \B9 𝟗 465 | -------------------------------------------------------------------------------- /MathSymbolsInput/InputController.m: -------------------------------------------------------------------------------- 1 | #import "InputController.h" 2 | 3 | #import "Commands.h" 4 | 5 | #ifdef DEBUG 6 | #define DLog(...) NSLog(__VA_ARGS__) 7 | #else 8 | #define DLog(...) 9 | #endif 10 | 11 | // Preferences app name. 12 | static NSString *kPreferencesAppBundleIdentifier = @"com.mathsymbolsinput.MathSymbolsInputPreferences"; 13 | // NSUserDefaults key for the preferences tab. 14 | static NSString *kPreferencesTabKey = @"PreferencesTab"; 15 | 16 | // Maximum number of characters that could be returned from UCKeyTranslate. 17 | const int kUCKeyTranslateBufferLength = 255; 18 | 19 | // See IMKInputController.h for documentation of the IMKServerInput protocol. 20 | @implementation InputController { 21 | // Buffer containing text that the user has input so far in the current 22 | // composition session. 23 | NSMutableString *compositionBuffer; 24 | 25 | // Dead key state for reading keyboard input. 26 | UInt32 deadKeyState; 27 | 28 | // Last dead key pressed, or empty string if the last key was not a dead key. 29 | NSString *lastDeadKey; 30 | 31 | // Menu displayed in the menu bar. 32 | NSMenu *menu; 33 | } 34 | 35 | // Initializes the input controller. 36 | - (id)initWithServer:(IMKServer *)server delegate:(id)delegate client:(id)inputClient { 37 | self = [super initWithServer:server delegate:delegate client:inputClient]; 38 | if (self) { 39 | compositionBuffer = [[NSMutableString alloc] init]; 40 | deadKeyState = 0; 41 | lastDeadKey = @""; 42 | 43 | menu = [[NSMenu alloc] init]; 44 | [menu addItemWithTitle:@"View Default Commands..." action:@selector(showDefaultCommands:) keyEquivalent:@""]; 45 | [menu addItemWithTitle:@"Edit Custom Commands..." action:@selector(showCustomCommands:) keyEquivalent:@""]; 46 | [menu addItemWithTitle:@"About" action:@selector(showAbout:) keyEquivalent:@""]; 47 | } 48 | return self; 49 | } 50 | 51 | // Update the client's state match the composition plus any dead keys. This 52 | // must be called whenever the composition or dead key state changes. 53 | - (void)updateMarkedText { 54 | NSString *markedText = [compositionBuffer stringByAppendingString:lastDeadKey]; 55 | // Seems like using an NSAttributedString for setMarkedText is necessary to 56 | // get the cursor to appear at the end of the marked text instead of selecting 57 | // the whole range. 58 | NSDictionary *attrs = [self markForStyle:kTSMHiliteSelectedRawText 59 | atRange:NSMakeRange(0, [markedText length])]; 60 | NSAttributedString *attrString = 61 | [[NSAttributedString alloc] initWithString:markedText attributes:attrs]; 62 | [[self client] setMarkedText:attrString 63 | selectionRange:NSMakeRange([markedText length], 0) 64 | replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; 65 | } 66 | 67 | // Sends text for the client to insert. 68 | - (void)insertText:(NSString *)string { 69 | if ([string length] > 0) { 70 | [[self client] insertText:string replacementRange:NSMakeRange(NSNotFound, NSNotFound)]; 71 | } 72 | } 73 | 74 | // Accepts the currently-chosen replacement. 75 | - (void)accept { 76 | NSString *replacement = findReplacement(compositionBuffer); 77 | NSString *acceptedString = replacement != nil ? replacement : compositionBuffer; 78 | [self insertText:acceptedString]; 79 | [compositionBuffer setString:@""]; 80 | [self updateMarkedText]; 81 | } 82 | 83 | // Inserts the contents of the buffer without making a replacement, returning to 84 | // an inactive state. 85 | - (void)deactivate { 86 | [self insertText:compositionBuffer]; 87 | 88 | [compositionBuffer setString:@""]; 89 | deadKeyState = 0; 90 | lastDeadKey = @""; 91 | 92 | [self updateMarkedText]; 93 | } 94 | 95 | // Returns a Unicode representation of a keydown event, or nil if the event 96 | // should not be handled by us. 97 | - (NSString *)readCharacters:(NSEvent *)event { 98 | if ([event type] != NSEventTypeKeyDown) { 99 | return nil; 100 | } 101 | 102 | unsigned short keyCode = [event keyCode]; 103 | NSEventModifierFlags modifierFlags = [event modifierFlags]; 104 | // Skip events with control or command held, since these are probably 105 | // keyboard shortcuts. 106 | if (modifierFlags & NSEventModifierFlagControl || 107 | modifierFlags & NSEventModifierFlagCommand) { 108 | return nil; 109 | } 110 | 111 | TISInputSourceRef inputSource = TISCopyCurrentASCIICapableKeyboardLayoutInputSource(); 112 | CFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(inputSource, kTISPropertyUnicodeKeyLayoutData); 113 | if (layoutData == nil) { 114 | NSLog(@"No keyboard layout data"); 115 | return nil; 116 | } 117 | const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *) CFDataGetBytePtr(layoutData); 118 | UInt32 keyboardType = (UInt32) CGEventGetIntegerValueField([event CGEvent], kCGKeyboardEventKeyboardType); 119 | 120 | int unicodeModifiers = 0; 121 | if (modifierFlags & NSEventModifierFlagShift) unicodeModifiers |= shiftKey; 122 | if (modifierFlags & NSEventModifierFlagCapsLock) unicodeModifiers |= alphaLock; 123 | if (modifierFlags & NSEventModifierFlagOption) unicodeModifiers |= optionKey; 124 | UInt32 modifierKeyState = (unicodeModifiers >> 8) & 0xFF; 125 | 126 | UniChar buffer[kUCKeyTranslateBufferLength]; 127 | UniCharCount resultLength; 128 | OSStatus status = UCKeyTranslate(keyboardLayout, 129 | keyCode, 130 | kUCKeyActionDown, 131 | modifierKeyState, 132 | keyboardType, 133 | 0, 134 | &deadKeyState, 135 | kUCKeyTranslateBufferLength, 136 | &resultLength, 137 | buffer); 138 | 139 | if (status != noErr) { 140 | NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; 141 | NSLog(@"Could not translate key: %@", [error localizedDescription]); 142 | return nil; 143 | } 144 | 145 | NSString *string = [[NSString alloc] initWithCharacters:buffer length:resultLength]; 146 | 147 | // It appears that the low bytes of deadKeyState is the current state, while 148 | // the high bytes are the previous state. So if the low bytes are nonzero, 149 | // we're currently in a dead key state. We call UCKeyTranslate again with 150 | // dead key processing turned off to find out what the dead key was. 151 | if ((deadKeyState & 0xFFFF) != 0) { 152 | UInt32 unusedDeadKeyState = 0; 153 | status = UCKeyTranslate(keyboardLayout, 154 | keyCode, 155 | kUCKeyActionDown, 156 | modifierKeyState, 157 | keyboardType, 158 | kUCKeyTranslateNoDeadKeysMask, 159 | &unusedDeadKeyState, 160 | kUCKeyTranslateBufferLength, 161 | &resultLength, 162 | buffer); 163 | 164 | if (status != noErr) { 165 | NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil]; 166 | NSLog(@"Could not translate dead key: %@", [error localizedDescription]); 167 | return nil; 168 | } 169 | 170 | lastDeadKey = [[NSString alloc] initWithCharacters:buffer length:resultLength]; 171 | } else { 172 | lastDeadKey = @""; 173 | } 174 | 175 | DLog(@"readCharacters string:%@ deadKeyState:0x%x lastDeadKey:%@", string, deadKeyState, lastDeadKey); 176 | return string; 177 | } 178 | 179 | // Called by InputMethodKit on keydown events. This method should return YES if 180 | // we've handled the event, and NO if the event should be passed to the client 181 | // instead. We ensure that the composition is inactive before passing any events 182 | // on to the client to prevent surprising behavior. 183 | - (BOOL)handleEvent:(NSEvent *)event client:(id)sender { 184 | DLog(@"handleEvent event:(%@) client:%@", [event debugDescription], [[self client] bundleIdentifier]); 185 | NSString* string = [self readCharacters:event]; 186 | if (string == nil) { 187 | [self deactivate]; 188 | return NO; 189 | } 190 | 191 | // Keyboard layouts use ASCII control codes to represent special keys 192 | // like backspace or the arrow keys. They could be preceded by normal text 193 | // if the user presses a dead key before the special key. Anecdotally it 194 | // seems like it's not allowed to have a keyboard layout that emits more than 195 | // one control character, or a control character in the middle of a string. 196 | // 197 | // We also treat backslash and space as "control codes" here since they are 198 | // also treated specially by the input method. This does mean that these 199 | // characters would not be handled if they're in the middle of the input 200 | // string, but it's not clear what we should do in that case anyway. 201 | unichar controlCode = 0; 202 | NSUInteger length = [string length]; 203 | if (length > 0) { 204 | unichar c = [string characterAtIndex:(length - 1)]; 205 | if (c <= 0x20 || /* C0 control codes and space */ 206 | c == 0x5c || /* backslash */ 207 | (c >= 0x7f && c <= 0x9f) /* C1 control codes */) { 208 | controlCode = c; 209 | string = [string substringToIndex:(length - 1)]; 210 | } 211 | } 212 | 213 | if ([compositionBuffer length] == 0) { // no active composition 214 | [self insertText:string]; 215 | [self updateMarkedText]; 216 | 217 | // normal typing 218 | if (controlCode == 0) { 219 | return YES; 220 | } 221 | // backslash: start a new composition 222 | if (controlCode == '\\') { 223 | [compositionBuffer appendString:@"\\"]; 224 | [self updateMarkedText]; 225 | return YES; 226 | } 227 | } else { // active composition 228 | [compositionBuffer appendString:string]; 229 | [self updateMarkedText]; 230 | 231 | // normal typing 232 | if (controlCode == 0) { 233 | return YES; 234 | } 235 | // enter or tab: accept current composition 236 | if (controlCode == '\r' || controlCode == '\t') { 237 | [self accept]; 238 | return YES; 239 | } 240 | // space: accept current composition and insert space 241 | if (controlCode == ' ') { 242 | [self accept]; 243 | [self insertText:@" "]; 244 | return YES; 245 | } 246 | // backslash: accept current composition and start a new one 247 | if (controlCode == '\\') { 248 | [self accept]; 249 | [compositionBuffer appendString:@"\\"]; 250 | [self updateMarkedText]; 251 | return YES; 252 | } 253 | // backspace: remove last grapheme cluster from composition 254 | if (controlCode == 0x08) { 255 | NSRange range = [compositionBuffer rangeOfComposedCharacterSequenceAtIndex:[compositionBuffer length] - 1]; 256 | [compositionBuffer deleteCharactersInRange:range]; 257 | [self updateMarkedText]; 258 | return YES; 259 | } 260 | // escape: deactivate 261 | if (controlCode == 0x1b) { 262 | [self deactivate]; 263 | return YES; 264 | } 265 | } 266 | 267 | // For all other cases, deactivate and let the client handle the event. 268 | [self deactivate]; 269 | return NO; 270 | } 271 | 272 | // Called by InputMethodKit when the client wants to end composition immediately 273 | // (e.g. the user selected a new input method, or clicked outside of the marked 274 | // text). 275 | - (void)commitComposition:(id)sender { 276 | DLog(@"commitComposition client:%@", [[self client] bundleIdentifier]); 277 | [self deactivate]; 278 | } 279 | 280 | // Called by InputMethodKit when the client gains focus. 281 | - (void)activateServer:(id)sender { 282 | DLog(@"activateServer client:%@", [[self client] bundleIdentifier]); 283 | } 284 | 285 | // Called by InputMethodKit when the client loses focus. 286 | - (void)deactivateServer:(id)sender { 287 | DLog(@"deactivateServer client:%@", [[self client] bundleIdentifier]); 288 | [self deactivate]; 289 | } 290 | 291 | // Called by InputMethodKit to display a menu in the menu bar. 292 | - (NSMenu *)menu { 293 | return menu; 294 | } 295 | 296 | // Opens the preferences app the the given tab, which is communicated to the 297 | // preferences app via NSUserDefaults. 298 | - (void)openPreferences:(NSString *)tabId { 299 | [[NSUserDefaults standardUserDefaults] setObject:tabId forKey:kPreferencesTabKey]; 300 | NSURL *url = [[NSWorkspace sharedWorkspace] URLForApplicationWithBundleIdentifier:kPreferencesAppBundleIdentifier]; 301 | if (url == nil) { 302 | NSLog(@"Could not find preferences application with bundle id %@", kPreferencesAppBundleIdentifier); 303 | return; 304 | } 305 | NSLog(@"Opening preferences tab %@ with URL: %@", tabId, [url absoluteString]); 306 | [[NSWorkspace sharedWorkspace] openURL:url]; 307 | } 308 | 309 | - (void)showDefaultCommands:(id)sender { 310 | [self openPreferences:@"default-commands"]; 311 | } 312 | 313 | - (void)showCustomCommands:(id)sender { 314 | [self openPreferences:@"custom-commands"]; 315 | } 316 | 317 | - (void)showAbout:(id)sender { 318 | [self openPreferences:@"about"]; 319 | } 320 | 321 | @end 322 | -------------------------------------------------------------------------------- /MathSymbolsInput.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1A16BB4923B907E000E667C4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A16BB4823B907E000E667C4 /* AppDelegate.swift */; }; 11 | 1A16BB4B23B907E000E667C4 /* CustomCommandsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A16BB4A23B907E000E667C4 /* CustomCommandsController.swift */; }; 12 | 1A16BB4D23B907E100E667C4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A16BB4C23B907E100E667C4 /* Assets.xcassets */; }; 13 | 1A16BB5023B907E100E667C4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1A16BB4E23B907E100E667C4 /* Main.storyboard */; }; 14 | 1A676D4A23BBAA730092EF01 /* TabController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A676D4923BBAA730092EF01 /* TabController.swift */; }; 15 | 1A67768F2968D5B7007D5C04 /* Commands.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A67768E2968D5B7007D5C04 /* Commands.m */; }; 16 | 1A6776922968E5CF007D5C04 /* InputController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A6776912968E5CF007D5C04 /* InputController.m */; }; 17 | 1A6776952968ECBA007D5C04 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A6776942968ECBA007D5C04 /* main.m */; }; 18 | 1A695F26229F8FDD008DEC0F /* commands.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1A695F25229F8FDD008DEC0F /* commands.txt */; }; 19 | 1A6DBD6223B969C600AA8924 /* DefaultCommandsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A6DBD6023B966B900AA8924 /* DefaultCommandsController.swift */; }; 20 | 1A6DBD6623B9A63C00AA8924 /* AboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A6DBD6523B9A63C00AA8924 /* AboutController.swift */; }; 21 | 1A8EF34F296B6A030006D7FC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A8EF34E296B6A030006D7FC /* main.m */; }; 22 | 1AC14D8B22AE875100549402 /* icon.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 1AC14D8A22AE875100549402 /* icon.pdf */; }; 23 | 1AC76A9D23B6D9D0009BD2D7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1AC76A9B23B6D9D0009BD2D7 /* InfoPlist.strings */; }; 24 | F61A7AD61E818BF300EBF660 /* InputMethodKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F61A7AD51E818BF300EBF660 /* InputMethodKit.framework */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXCopyFilesBuildPhase section */ 28 | 1A8EF34A296B6A030006D7FC /* CopyFiles */ = { 29 | isa = PBXCopyFilesBuildPhase; 30 | buildActionMask = 2147483647; 31 | dstPath = /usr/share/man/man1/; 32 | dstSubfolderSpec = 0; 33 | files = ( 34 | ); 35 | runOnlyForDeploymentPostprocessing = 1; 36 | }; 37 | /* End PBXCopyFilesBuildPhase section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 1A10FC3423BD7EBE00556BCE /* uninstall.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = uninstall.sh; sourceTree = ""; }; 41 | 1A10FC3523BD824C00556BCE /* MathSymbolsInputPreferences-components.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MathSymbolsInputPreferences-components.plist"; sourceTree = ""; }; 42 | 1A10FC3623BD824C00556BCE /* MathSymbolsInput-components.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MathSymbolsInput-components.plist"; sourceTree = ""; }; 43 | 1A16BB4623B907E000E667C4 /* Math Symbols Input - Preferences.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Math Symbols Input - Preferences.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 1A16BB4823B907E000E667C4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 45 | 1A16BB4A23B907E000E667C4 /* CustomCommandsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomCommandsController.swift; sourceTree = ""; }; 46 | 1A16BB4C23B907E100E667C4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = MathSymbolsInputPreferences/Assets.xcassets; sourceTree = SOURCE_ROOT; }; 47 | 1A16BB4F23B907E100E667C4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 48 | 1A16BB5123B907E100E667C4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | 1A5DB37A22AE8DCA000F7F92 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 50 | 1A5DB37C22AE8E24000F7F92 /* install.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = install.sh; sourceTree = ""; }; 51 | 1A676D4923BBAA730092EF01 /* TabController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabController.swift; sourceTree = ""; }; 52 | 1A67768E2968D5B7007D5C04 /* Commands.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Commands.m; sourceTree = ""; }; 53 | 1A6776902968D5C5007D5C04 /* Commands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Commands.h; sourceTree = ""; }; 54 | 1A6776912968E5CF007D5C04 /* InputController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InputController.m; sourceTree = ""; }; 55 | 1A6776932968E5E9007D5C04 /* InputController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InputController.h; sourceTree = ""; }; 56 | 1A6776942968ECBA007D5C04 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 57 | 1A695F25229F8FDD008DEC0F /* commands.txt */ = {isa = PBXFileReference; indentWidth = 8; lastKnownFileType = text; path = commands.txt; sourceTree = ""; tabWidth = 8; usesTabs = 1; }; 58 | 1A6DBD6023B966B900AA8924 /* DefaultCommandsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultCommandsController.swift; sourceTree = ""; }; 59 | 1A6DBD6523B9A63C00AA8924 /* AboutController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutController.swift; sourceTree = ""; }; 60 | 1A6DBD9B23BA62EC00AA8924 /* distribution.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = distribution.xml; sourceTree = ""; }; 61 | 1A6DBD9C23BA62EC00AA8924 /* package.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = package.sh; sourceTree = ""; }; 62 | 1A6DBD9D23BA666B00AA8924 /* DEVELOPMENT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = DEVELOPMENT.md; sourceTree = ""; }; 63 | 1A6DBD9E23BA6F3500AA8924 /* InstallerSections.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = InstallerSections.plist; sourceTree = ""; }; 64 | 1A8EF34C296B6A030006D7FC /* activate */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = activate; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 1A8EF34E296B6A030006D7FC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 66 | 1AC14D8A22AE875100549402 /* icon.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = icon.pdf; sourceTree = ""; }; 67 | 1AC76A9C23B6D9D0009BD2D7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = ""; }; 68 | 1AC9635C23BCFB7F00A67BC1 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 69 | 1AC9635E23BCFFC900A67BC1 /* demo.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = demo.gif; sourceTree = ""; }; 70 | F61A7ABB1E8182C100EBF660 /* Math Symbols Input.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Math Symbols Input.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 71 | F61A7ACC1E8182C100EBF660 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 72 | F61A7AD51E818BF300EBF660 /* InputMethodKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = InputMethodKit.framework; path = System/Library/Frameworks/InputMethodKit.framework; sourceTree = SDKROOT; }; 73 | /* End PBXFileReference section */ 74 | 75 | /* Begin PBXFrameworksBuildPhase section */ 76 | 1A16BB4323B907E000E667C4 /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | 1A8EF349296B6A030006D7FC /* Frameworks */ = { 84 | isa = PBXFrameworksBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | F61A7AB81E8182C100EBF660 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | F61A7AD61E818BF300EBF660 /* InputMethodKit.framework in Frameworks */, 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXFrameworksBuildPhase section */ 99 | 100 | /* Begin PBXGroup section */ 101 | 1A16BB4723B907E000E667C4 /* MathSymbolsInputPreferences */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 1A16BB5123B907E100E667C4 /* Info.plist */, 105 | 1A16BB4C23B907E100E667C4 /* Assets.xcassets */, 106 | 1A16BB4E23B907E100E667C4 /* Main.storyboard */, 107 | 1A6DBD6523B9A63C00AA8924 /* AboutController.swift */, 108 | 1A16BB4823B907E000E667C4 /* AppDelegate.swift */, 109 | 1A16BB4A23B907E000E667C4 /* CustomCommandsController.swift */, 110 | 1A6DBD6023B966B900AA8924 /* DefaultCommandsController.swift */, 111 | 1A676D4923BBAA730092EF01 /* TabController.swift */, 112 | ); 113 | path = MathSymbolsInputPreferences; 114 | sourceTree = ""; 115 | }; 116 | 1A8EF34D296B6A030006D7FC /* activate */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 1A8EF34E296B6A030006D7FC /* main.m */, 120 | ); 121 | path = activate; 122 | sourceTree = ""; 123 | }; 124 | F61A7AB21E8182C100EBF660 = { 125 | isa = PBXGroup; 126 | children = ( 127 | 1AC9635C23BCFB7F00A67BC1 /* LICENSE */, 128 | 1A5DB37A22AE8DCA000F7F92 /* README.md */, 129 | 1A6DBD9D23BA666B00AA8924 /* DEVELOPMENT.md */, 130 | 1AC9635E23BCFFC900A67BC1 /* demo.gif */, 131 | 1A5DB37C22AE8E24000F7F92 /* install.sh */, 132 | 1A10FC3423BD7EBE00556BCE /* uninstall.sh */, 133 | 1A6DBD9C23BA62EC00AA8924 /* package.sh */, 134 | 1A10FC3623BD824C00556BCE /* MathSymbolsInput-components.plist */, 135 | 1A10FC3523BD824C00556BCE /* MathSymbolsInputPreferences-components.plist */, 136 | 1A6DBD9E23BA6F3500AA8924 /* InstallerSections.plist */, 137 | 1A6DBD9B23BA62EC00AA8924 /* distribution.xml */, 138 | F61A7ABD1E8182C100EBF660 /* MathSymbolsInput */, 139 | 1A16BB4723B907E000E667C4 /* MathSymbolsInputPreferences */, 140 | 1A8EF34D296B6A030006D7FC /* activate */, 141 | F61A7ABC1E8182C100EBF660 /* Products */, 142 | F61A7AD41E818BF300EBF660 /* Frameworks */, 143 | ); 144 | sourceTree = ""; 145 | }; 146 | F61A7ABC1E8182C100EBF660 /* Products */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | F61A7ABB1E8182C100EBF660 /* Math Symbols Input.app */, 150 | 1A16BB4623B907E000E667C4 /* Math Symbols Input - Preferences.app */, 151 | 1A8EF34C296B6A030006D7FC /* activate */, 152 | ); 153 | name = Products; 154 | sourceTree = ""; 155 | }; 156 | F61A7ABD1E8182C100EBF660 /* MathSymbolsInput */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | F61A7ACC1E8182C100EBF660 /* Info.plist */, 160 | 1AC76A9B23B6D9D0009BD2D7 /* InfoPlist.strings */, 161 | 1A695F25229F8FDD008DEC0F /* commands.txt */, 162 | 1AC14D8A22AE875100549402 /* icon.pdf */, 163 | 1A6776902968D5C5007D5C04 /* Commands.h */, 164 | 1A67768E2968D5B7007D5C04 /* Commands.m */, 165 | 1A6776932968E5E9007D5C04 /* InputController.h */, 166 | 1A6776912968E5CF007D5C04 /* InputController.m */, 167 | 1A6776942968ECBA007D5C04 /* main.m */, 168 | ); 169 | path = MathSymbolsInput; 170 | sourceTree = ""; 171 | }; 172 | F61A7AD41E818BF300EBF660 /* Frameworks */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | F61A7AD51E818BF300EBF660 /* InputMethodKit.framework */, 176 | ); 177 | name = Frameworks; 178 | sourceTree = ""; 179 | }; 180 | /* End PBXGroup section */ 181 | 182 | /* Begin PBXNativeTarget section */ 183 | 1A16BB4523B907E000E667C4 /* Math Symbols Input - Preferences */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 1A16BB5523B907E100E667C4 /* Build configuration list for PBXNativeTarget "Math Symbols Input - Preferences" */; 186 | buildPhases = ( 187 | 1A16BB4223B907E000E667C4 /* Sources */, 188 | 1A16BB4323B907E000E667C4 /* Frameworks */, 189 | 1A16BB4423B907E000E667C4 /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | ); 195 | name = "Math Symbols Input - Preferences"; 196 | productName = "Math Symbols Input - Preferences"; 197 | productReference = 1A16BB4623B907E000E667C4 /* Math Symbols Input - Preferences.app */; 198 | productType = "com.apple.product-type.application"; 199 | }; 200 | 1A8EF34B296B6A030006D7FC /* activate */ = { 201 | isa = PBXNativeTarget; 202 | buildConfigurationList = 1A8EF352296B6A030006D7FC /* Build configuration list for PBXNativeTarget "activate" */; 203 | buildPhases = ( 204 | 1A8EF348296B6A030006D7FC /* Sources */, 205 | 1A8EF349296B6A030006D7FC /* Frameworks */, 206 | 1A8EF34A296B6A030006D7FC /* CopyFiles */, 207 | ); 208 | buildRules = ( 209 | ); 210 | dependencies = ( 211 | ); 212 | name = activate; 213 | productName = activate; 214 | productReference = 1A8EF34C296B6A030006D7FC /* activate */; 215 | productType = "com.apple.product-type.tool"; 216 | }; 217 | F61A7ABA1E8182C100EBF660 /* Math Symbols Input */ = { 218 | isa = PBXNativeTarget; 219 | buildConfigurationList = F61A7ACF1E8182C100EBF660 /* Build configuration list for PBXNativeTarget "Math Symbols Input" */; 220 | buildPhases = ( 221 | F61A7AB71E8182C100EBF660 /* Sources */, 222 | F61A7AB81E8182C100EBF660 /* Frameworks */, 223 | F61A7AB91E8182C100EBF660 /* Resources */, 224 | ); 225 | buildRules = ( 226 | ); 227 | dependencies = ( 228 | ); 229 | name = "Math Symbols Input"; 230 | productName = "Math Symbols Input"; 231 | productReference = F61A7ABB1E8182C100EBF660 /* Math Symbols Input.app */; 232 | productType = "com.apple.product-type.application"; 233 | }; 234 | /* End PBXNativeTarget section */ 235 | 236 | /* Begin PBXProject section */ 237 | F61A7AB31E8182C100EBF660 /* Project object */ = { 238 | isa = PBXProject; 239 | attributes = { 240 | LastSwiftUpdateCheck = 1030; 241 | LastUpgradeCheck = 1320; 242 | ORGANIZATIONNAME = ""; 243 | TargetAttributes = { 244 | 1A16BB4523B907E000E667C4 = { 245 | CreatedOnToolsVersion = 10.3; 246 | SystemCapabilities = { 247 | com.apple.Sandbox = { 248 | enabled = 0; 249 | }; 250 | }; 251 | }; 252 | 1A8EF34B296B6A030006D7FC = { 253 | CreatedOnToolsVersion = 13.2.1; 254 | }; 255 | F61A7ABA1E8182C100EBF660 = { 256 | CreatedOnToolsVersion = 8.2.1; 257 | LastSwiftMigration = 1320; 258 | ProvisioningStyle = Automatic; 259 | }; 260 | }; 261 | }; 262 | buildConfigurationList = F61A7AB61E8182C100EBF660 /* Build configuration list for PBXProject "MathSymbolsInput" */; 263 | compatibilityVersion = "Xcode 10.0"; 264 | developmentRegion = en; 265 | hasScannedForEncodings = 0; 266 | knownRegions = ( 267 | en, 268 | Base, 269 | ); 270 | mainGroup = F61A7AB21E8182C100EBF660; 271 | productRefGroup = F61A7ABC1E8182C100EBF660 /* Products */; 272 | projectDirPath = ""; 273 | projectRoot = ""; 274 | targets = ( 275 | F61A7ABA1E8182C100EBF660 /* Math Symbols Input */, 276 | 1A16BB4523B907E000E667C4 /* Math Symbols Input - Preferences */, 277 | 1A8EF34B296B6A030006D7FC /* activate */, 278 | ); 279 | }; 280 | /* End PBXProject section */ 281 | 282 | /* Begin PBXResourcesBuildPhase section */ 283 | 1A16BB4423B907E000E667C4 /* Resources */ = { 284 | isa = PBXResourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | 1A16BB4D23B907E100E667C4 /* Assets.xcassets in Resources */, 288 | 1A16BB5023B907E100E667C4 /* Main.storyboard in Resources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | F61A7AB91E8182C100EBF660 /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 1A695F26229F8FDD008DEC0F /* commands.txt in Resources */, 297 | 1AC14D8B22AE875100549402 /* icon.pdf in Resources */, 298 | 1AC76A9D23B6D9D0009BD2D7 /* InfoPlist.strings in Resources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | /* End PBXResourcesBuildPhase section */ 303 | 304 | /* Begin PBXSourcesBuildPhase section */ 305 | 1A16BB4223B907E000E667C4 /* Sources */ = { 306 | isa = PBXSourcesBuildPhase; 307 | buildActionMask = 2147483647; 308 | files = ( 309 | 1A676D4A23BBAA730092EF01 /* TabController.swift in Sources */, 310 | 1A6DBD6223B969C600AA8924 /* DefaultCommandsController.swift in Sources */, 311 | 1A16BB4B23B907E000E667C4 /* CustomCommandsController.swift in Sources */, 312 | 1A16BB4923B907E000E667C4 /* AppDelegate.swift in Sources */, 313 | 1A6DBD6623B9A63C00AA8924 /* AboutController.swift in Sources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | 1A8EF348296B6A030006D7FC /* Sources */ = { 318 | isa = PBXSourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | 1A8EF34F296B6A030006D7FC /* main.m in Sources */, 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | }; 325 | F61A7AB71E8182C100EBF660 /* Sources */ = { 326 | isa = PBXSourcesBuildPhase; 327 | buildActionMask = 2147483647; 328 | files = ( 329 | 1A67768F2968D5B7007D5C04 /* Commands.m in Sources */, 330 | 1A6776952968ECBA007D5C04 /* main.m in Sources */, 331 | 1A6776922968E5CF007D5C04 /* InputController.m in Sources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | /* End PBXSourcesBuildPhase section */ 336 | 337 | /* Begin PBXVariantGroup section */ 338 | 1A16BB4E23B907E100E667C4 /* Main.storyboard */ = { 339 | isa = PBXVariantGroup; 340 | children = ( 341 | 1A16BB4F23B907E100E667C4 /* Base */, 342 | ); 343 | name = Main.storyboard; 344 | sourceTree = ""; 345 | }; 346 | 1AC76A9B23B6D9D0009BD2D7 /* InfoPlist.strings */ = { 347 | isa = PBXVariantGroup; 348 | children = ( 349 | 1AC76A9C23B6D9D0009BD2D7 /* Base */, 350 | ); 351 | name = InfoPlist.strings; 352 | sourceTree = ""; 353 | }; 354 | /* End PBXVariantGroup section */ 355 | 356 | /* Begin XCBuildConfiguration section */ 357 | 1A16BB5323B907E100E667C4 /* Debug */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 363 | CLANG_ENABLE_OBJC_WEAK = YES; 364 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 365 | CODE_SIGN_IDENTITY = "-"; 366 | CODE_SIGN_STYLE = Automatic; 367 | COMBINE_HIDPI_IMAGES = YES; 368 | CONFIGURATION_BUILD_DIR = "$(inherited)"; 369 | GCC_C_LANGUAGE_STANDARD = gnu11; 370 | INFOPLIST_FILE = "$(SRCROOT)/MathSymbolsInputPreferences/Info.plist"; 371 | LD_RUNPATH_SEARCH_PATHS = ( 372 | "$(inherited)", 373 | "@executable_path/../Frameworks", 374 | ); 375 | MACOSX_DEPLOYMENT_TARGET = 10.10; 376 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 377 | MTL_FAST_MATH = YES; 378 | PRODUCT_BUNDLE_IDENTIFIER = com.mathsymbolsinput.MathSymbolsInputPreferences; 379 | PRODUCT_NAME = "$(TARGET_NAME)"; 380 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 381 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 382 | SWIFT_VERSION = 5.0; 383 | }; 384 | name = Debug; 385 | }; 386 | 1A16BB5423B907E100E667C4 /* Release */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 390 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 392 | CLANG_ENABLE_OBJC_WEAK = YES; 393 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 394 | CODE_SIGN_IDENTITY = "-"; 395 | CODE_SIGN_STYLE = Automatic; 396 | COMBINE_HIDPI_IMAGES = YES; 397 | CONFIGURATION_BUILD_DIR = "$(inherited)"; 398 | GCC_C_LANGUAGE_STANDARD = gnu11; 399 | INFOPLIST_FILE = "$(SRCROOT)/MathSymbolsInputPreferences/Info.plist"; 400 | LD_RUNPATH_SEARCH_PATHS = ( 401 | "$(inherited)", 402 | "@executable_path/../Frameworks", 403 | ); 404 | MACOSX_DEPLOYMENT_TARGET = 10.10; 405 | MTL_FAST_MATH = YES; 406 | PRODUCT_BUNDLE_IDENTIFIER = com.mathsymbolsinput.MathSymbolsInputPreferences; 407 | PRODUCT_NAME = "$(TARGET_NAME)"; 408 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 409 | SWIFT_VERSION = 5.0; 410 | }; 411 | name = Release; 412 | }; 413 | 1A8EF350296B6A030006D7FC /* Debug */ = { 414 | isa = XCBuildConfiguration; 415 | buildSettings = { 416 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 417 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 418 | CLANG_ENABLE_OBJC_WEAK = YES; 419 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 420 | CODE_SIGN_IDENTITY = "-"; 421 | CODE_SIGN_STYLE = Automatic; 422 | GCC_C_LANGUAGE_STANDARD = gnu11; 423 | MACOSX_DEPLOYMENT_TARGET = 11.6; 424 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 425 | MTL_FAST_MATH = YES; 426 | PRODUCT_NAME = "$(TARGET_NAME)"; 427 | }; 428 | name = Debug; 429 | }; 430 | 1A8EF351296B6A030006D7FC /* Release */ = { 431 | isa = XCBuildConfiguration; 432 | buildSettings = { 433 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 434 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 435 | CLANG_ENABLE_OBJC_WEAK = YES; 436 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 437 | CODE_SIGN_IDENTITY = "-"; 438 | CODE_SIGN_STYLE = Automatic; 439 | GCC_C_LANGUAGE_STANDARD = gnu11; 440 | MACOSX_DEPLOYMENT_TARGET = 11.6; 441 | MTL_FAST_MATH = YES; 442 | PRODUCT_NAME = "$(TARGET_NAME)"; 443 | }; 444 | name = Release; 445 | }; 446 | F61A7ACD1E8182C100EBF660 /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ALWAYS_SEARCH_USER_PATHS = NO; 450 | CLANG_ANALYZER_NONNULL = YES; 451 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 452 | CLANG_CXX_LIBRARY = "libc++"; 453 | CLANG_ENABLE_MODULES = YES; 454 | CLANG_ENABLE_OBJC_ARC = YES; 455 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 456 | CLANG_WARN_BOOL_CONVERSION = YES; 457 | CLANG_WARN_COMMA = YES; 458 | CLANG_WARN_CONSTANT_CONVERSION = YES; 459 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 460 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 461 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 462 | CLANG_WARN_EMPTY_BODY = YES; 463 | CLANG_WARN_ENUM_CONVERSION = YES; 464 | CLANG_WARN_INFINITE_RECURSION = YES; 465 | CLANG_WARN_INT_CONVERSION = YES; 466 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 467 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 468 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 469 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 470 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 471 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 472 | CLANG_WARN_STRICT_PROTOTYPES = YES; 473 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 474 | CLANG_WARN_UNREACHABLE_CODE = YES; 475 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 476 | CODE_SIGN_IDENTITY = ""; 477 | CONFIGURATION_BUILD_DIR = build/Debug; 478 | COPYRIGHT = "Copyright © 2020-2023 Kyle Raftogianis"; 479 | COPY_PHASE_STRIP = NO; 480 | DEBUG_INFORMATION_FORMAT = dwarf; 481 | ENABLE_STRICT_OBJC_MSGSEND = YES; 482 | ENABLE_TESTABILITY = YES; 483 | GCC_C_LANGUAGE_STANDARD = gnu99; 484 | GCC_DYNAMIC_NO_PIC = NO; 485 | GCC_NO_COMMON_BLOCKS = YES; 486 | GCC_OPTIMIZATION_LEVEL = 0; 487 | GCC_PREPROCESSOR_DEFINITIONS = ( 488 | "DEBUG=1", 489 | "$(inherited)", 490 | ); 491 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 492 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 493 | GCC_WARN_UNDECLARED_SELECTOR = YES; 494 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 495 | GCC_WARN_UNUSED_FUNCTION = YES; 496 | GCC_WARN_UNUSED_VARIABLE = YES; 497 | MACOSX_DEPLOYMENT_TARGET = 10.10; 498 | MTL_ENABLE_DEBUG_INFO = YES; 499 | ONLY_ACTIVE_ARCH = YES; 500 | SDKROOT = macosx; 501 | VERSION = 1.3; 502 | }; 503 | name = Debug; 504 | }; 505 | F61A7ACE1E8182C100EBF660 /* Release */ = { 506 | isa = XCBuildConfiguration; 507 | buildSettings = { 508 | ALWAYS_SEARCH_USER_PATHS = NO; 509 | CLANG_ANALYZER_NONNULL = YES; 510 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 511 | CLANG_CXX_LIBRARY = "libc++"; 512 | CLANG_ENABLE_MODULES = YES; 513 | CLANG_ENABLE_OBJC_ARC = YES; 514 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 515 | CLANG_WARN_BOOL_CONVERSION = YES; 516 | CLANG_WARN_COMMA = YES; 517 | CLANG_WARN_CONSTANT_CONVERSION = YES; 518 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 519 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 520 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 521 | CLANG_WARN_EMPTY_BODY = YES; 522 | CLANG_WARN_ENUM_CONVERSION = YES; 523 | CLANG_WARN_INFINITE_RECURSION = YES; 524 | CLANG_WARN_INT_CONVERSION = YES; 525 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 526 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 527 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 528 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 529 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 530 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 531 | CLANG_WARN_STRICT_PROTOTYPES = YES; 532 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 533 | CLANG_WARN_UNREACHABLE_CODE = YES; 534 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 535 | CODE_SIGN_IDENTITY = ""; 536 | CONFIGURATION_BUILD_DIR = build/Release; 537 | COPYRIGHT = "Copyright © 2020-2023 Kyle Raftogianis"; 538 | COPY_PHASE_STRIP = NO; 539 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 540 | ENABLE_NS_ASSERTIONS = NO; 541 | ENABLE_STRICT_OBJC_MSGSEND = YES; 542 | GCC_C_LANGUAGE_STANDARD = gnu99; 543 | GCC_NO_COMMON_BLOCKS = YES; 544 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 545 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 546 | GCC_WARN_UNDECLARED_SELECTOR = YES; 547 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 548 | GCC_WARN_UNUSED_FUNCTION = YES; 549 | GCC_WARN_UNUSED_VARIABLE = YES; 550 | MACOSX_DEPLOYMENT_TARGET = 10.10; 551 | MTL_ENABLE_DEBUG_INFO = NO; 552 | SDKROOT = macosx; 553 | SWIFT_COMPILATION_MODE = wholemodule; 554 | VERSION = 1.3; 555 | }; 556 | name = Release; 557 | }; 558 | F61A7AD01E8182C100EBF660 /* Debug */ = { 559 | isa = XCBuildConfiguration; 560 | buildSettings = { 561 | CLANG_ENABLE_MODULES = YES; 562 | CODE_SIGN_IDENTITY = "-"; 563 | COMBINE_HIDPI_IMAGES = YES; 564 | CONFIGURATION_BUILD_DIR = "$(inherited)"; 565 | INFOPLIST_FILE = "$(SRCROOT)/MathSymbolsInput/Info.plist"; 566 | LD_RUNPATH_SEARCH_PATHS = ( 567 | "$(inherited)", 568 | "@executable_path/../Frameworks", 569 | ); 570 | MACOSX_DEPLOYMENT_TARGET = 10.10; 571 | PRODUCT_BUNDLE_IDENTIFIER = com.mathsymbolsinput.inputmethod.MathSymbolsInput; 572 | PRODUCT_NAME = "$(TARGET_NAME)"; 573 | }; 574 | name = Debug; 575 | }; 576 | F61A7AD11E8182C100EBF660 /* Release */ = { 577 | isa = XCBuildConfiguration; 578 | buildSettings = { 579 | CLANG_ENABLE_MODULES = YES; 580 | CODE_SIGN_IDENTITY = "-"; 581 | COMBINE_HIDPI_IMAGES = YES; 582 | CONFIGURATION_BUILD_DIR = "$(inherited)"; 583 | INFOPLIST_FILE = "$(SRCROOT)/MathSymbolsInput/Info.plist"; 584 | LD_RUNPATH_SEARCH_PATHS = ( 585 | "$(inherited)", 586 | "@executable_path/../Frameworks", 587 | ); 588 | MACOSX_DEPLOYMENT_TARGET = 10.10; 589 | PRODUCT_BUNDLE_IDENTIFIER = com.mathsymbolsinput.inputmethod.MathSymbolsInput; 590 | PRODUCT_NAME = "$(TARGET_NAME)"; 591 | }; 592 | name = Release; 593 | }; 594 | /* End XCBuildConfiguration section */ 595 | 596 | /* Begin XCConfigurationList section */ 597 | 1A16BB5523B907E100E667C4 /* Build configuration list for PBXNativeTarget "Math Symbols Input - Preferences" */ = { 598 | isa = XCConfigurationList; 599 | buildConfigurations = ( 600 | 1A16BB5323B907E100E667C4 /* Debug */, 601 | 1A16BB5423B907E100E667C4 /* Release */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | 1A8EF352296B6A030006D7FC /* Build configuration list for PBXNativeTarget "activate" */ = { 607 | isa = XCConfigurationList; 608 | buildConfigurations = ( 609 | 1A8EF350296B6A030006D7FC /* Debug */, 610 | 1A8EF351296B6A030006D7FC /* Release */, 611 | ); 612 | defaultConfigurationIsVisible = 0; 613 | defaultConfigurationName = Release; 614 | }; 615 | F61A7AB61E8182C100EBF660 /* Build configuration list for PBXProject "MathSymbolsInput" */ = { 616 | isa = XCConfigurationList; 617 | buildConfigurations = ( 618 | F61A7ACD1E8182C100EBF660 /* Debug */, 619 | F61A7ACE1E8182C100EBF660 /* Release */, 620 | ); 621 | defaultConfigurationIsVisible = 0; 622 | defaultConfigurationName = Release; 623 | }; 624 | F61A7ACF1E8182C100EBF660 /* Build configuration list for PBXNativeTarget "Math Symbols Input" */ = { 625 | isa = XCConfigurationList; 626 | buildConfigurations = ( 627 | F61A7AD01E8182C100EBF660 /* Debug */, 628 | F61A7AD11E8182C100EBF660 /* Release */, 629 | ); 630 | defaultConfigurationIsVisible = 0; 631 | defaultConfigurationName = Release; 632 | }; 633 | /* End XCConfigurationList section */ 634 | }; 635 | rootObject = F61A7AB31E8182C100EBF660 /* Project object */; 636 | } 637 | -------------------------------------------------------------------------------- /MathSymbolsInputPreferences/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 378 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 513 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | --------------------------------------------------------------------------------