diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m index 824f8a5b03..44b6bf100d 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodEventHandler.m @@ -525,8 +525,22 @@ NSRange _previousSelRange; /*if (event.type == NSKeyDown) [self.AppDelegate handleKeyEvent:event];*/ - if (event.type == NSFlagsChanged) { - _contextOutOfDate = YES; + if (event.type == NSEventTypeFlagsChanged) { + // We mark the context as out of date only for the Command keys + switch([event keyCode]) { + case kVK_RightCommand: + case kVK_Command: + _contextOutOfDate = YES; + break; + case kVK_Shift: + case kVK_RightShift: + case kVK_CapsLock: + case kVK_Option: + case kVK_RightOption: + case kVK_Control: + case kVK_RightControl: + break; + } return NO; } diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/Categories/NSString+XString.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/Categories/NSString+XString.m index d54c4233c2..f7d5c8c882 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/Categories/NSString+XString.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/Categories/NSString+XString.m @@ -322,7 +322,7 @@ } } else { - [mStr appendString:[NSString stringWithFormat:@"%C", c]]; + [mStr appendString:[NSString stringWithFormat:@"U+%x", c]]; i++; } } diff --git a/mac/README.md b/mac/README.md index 96d001ef86..bc21813ee1 100644 --- a/mac/README.md +++ b/mac/README.md @@ -1,16 +1,34 @@ # Keyman for macOS ## Mac Tools Requirements/Setup -Install Xcode 8.3.3 or later (it might also work to use an older version) + +Install Xcode 11.3.1 or later (it might also work to use an older version) Install [Carthage](https://github.com/Carthage/Carthage/blob/master/README.md) *see Homebrew note below Install cocoapods (sudo gem install cocoapods) if not already installed. ## Keyman for macOS Development + Keyman for macOS can be built from a command line (preferred) or Xcode. ### Setting up your code signing and notarization environment. -With macOS 10.14 and later, Keyman must be signed then notarized by Apple, even for local -test builds. This requires additional configuration for your build environment. + +With macOS 10.14 and later, Keyman must be notarized in order to be permitted to interact with +keyboard input. You have two options for local builds: + +1. You can disable security checks for the system with the command: + + `sudo spctl --master-disable` + + This has obvious security implications and the risk is up to you. However, builds are + much, much, faster than with the alternative option below, and for extensive local + debugging is far less painful. + +2. Or, you must sign and notarize every build. See below. (Use --deploy local) + +### Signing and notarizing builds + +Keyman must be signed then notarized by Apple, even for local test builds. This requires additional +configuration for your build environment. 1. First, open XCode, Preferences, Accounts, and select Manage Certificates for the identity you wish to use for signing. Click **+** and select **Developer ID Application**. A @@ -37,6 +55,7 @@ test builds. This requires additional configuration for your build environment. export APPSTORECONNECT_PASSWORD= ### Compiling from Command Line + To build Keyman for macOS, do the following: 1. Open a Terminal window. 2. cd to **keyman/mac**. **build.sh** must be run in the directory containing the script. @@ -48,15 +67,17 @@ To build Keyman for macOS, do the following: Note: If Carthage prompts you to allow it access to your github credentials, it's fine to click Deny. ### Running Keyman + 1. Deploy Keyman locally using `./build.sh -deploy local -deploy-only`. * This will notarize the app, signing with your local credentials if not already signed, and copy **keyman/mac/Keyman4MacIM/build/Debug/Keyman.app** to **~/Library/Input Methods** 2. If running for the first time, follow the installation instructions at [Installing Keyman for Mac OS X](https://help.keyman.com/products/mac/1.0/docs/start_download-install_keyman.php). You can also use `./build.sh -no-codesign -deploy local` to do a single-step build, notarize, -and deploy. +and deploy (see above for faster options). ### Compiling from Xcode + To build using Xcode, you will need to build KeymanEngine4Mac first and then build Keyman4MacIM. The very _first_ time after getting the source code (and any time the Podfile is edited; e.g., to install new pods), you need to go to **keyman/mac/Keyman4MacIM** and run "pod install" in Terminal. 1. Launch Xcode @@ -71,16 +92,18 @@ To build using Xcode, you will need to build KeymanEngine4Mac first and then bui 6. Build the project. Refer to [Running Keyman](#running-keyman) on how to install the app. ### Testing + The Keyman4Mac project builds a test-bed app that can be used to test keyboards without installing the input method. It can also be used as reference for the usage of Keyman Engine. Keyman4Mac tests are run using `./build.sh -test -no-codesign`. -*note about Homebrew: -Installing Carthage directly from the pkg file is simple. Homebrew seemed simple, but it -changes a lot of settings and I think it messed up the build in a way that took me a long -time to sort out. One specific problem is that using Homebrew seems to mess up the -command-line tools, so you will probably get this error from xcodebuild: - Error: xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory is a command line tools instance -To fix it run this command: - sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer +### A note about Homebrew and xcodebuild + +If you get this error from xcodebuild: + +`Error: xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory is a command line tools instance` + +Then run this command to fix the build environment: + +`sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer` diff --git a/mac/build.sh b/mac/build.sh index 3d46c1cb09..b8a450db90 100755 --- a/mac/build.sh +++ b/mac/build.sh @@ -14,6 +14,7 @@ display_usage() { echo " -deploy DEST Deploys result of Keyman4MacIM. DEST options:" echo " n|none (default) Not deployed." echo " l|local $HOME/Library/Input Methods (kills running process if needed)" + echo " q|quicklocal Same as local but does not notarize the build (see README.md)" echo " p|preprelease Builds a DMG and download_info file in output\upload." echo " -deploy-only Suppresses build/clean/test for all targets." echo " -tier TIER Used with -deploy p to specify tier: alpha (default), beta, or stable." @@ -128,6 +129,7 @@ BUILD_ACTIONS="build" TEST_ACTION="" CLEAN=false QUIET=false +NOTARIZE=false SKIP_BUILD=false # Parse args @@ -142,9 +144,15 @@ while [[ $# -gt 0 ]] ; do # the deployed version cannot be run in the debugger. if [[ "$2" =~ ^(l(ocal)?)$ ]]; then LOCALDEPLOY=true + NOTARIZE=true + CONFIG="Release" + elif [[ "$2" =~ ^(q(uick(local)?)?)$ ]]; then + LOCALDEPLOY=true + NOTARIZE=false CONFIG="Release" elif [[ "$2" =~ ^(p(rep(release)?)?)$ ]]; then PREPRELEASE=true + NOTARIZE=true CONFIG="Release" elif ! [[ "$2" =~ ^(n(one)?)$ ]]; then fail "Invalid deploy option. Must be 'none', 'local' or 'preprelease'." @@ -265,7 +273,16 @@ displayInfo "" \ ### Validate notarization environment variables ### -if $LOCALDEPLOY || $PREPRELEASE ; then +if $LOCALDEPLOY && ! $NOTARIZE ; then + if [ "$(spctl --status)" == "assessments enabled" ]; then + echo + warn "WARNING: Notarization is disabled but SecAssessment security policy is still active. Keyman will not run correctly." + warn " Disable SecAssessment with 'sudo spctl --master-disable' (or do notarized builds)" + fail "Re-run with '-deploy local' or disable SecAssessment." + fi +fi + +if $PREPRELEASE || $NOTARIZE ; then if [ "${CODESIGNING_SUPPRESSION}" != "" ] && [ -z "${CERTIFICATE_ID}" ]; then fail "Code signing must be configured for deployment. See build.sh -help for details." fi @@ -370,9 +387,9 @@ if $DO_KEYMANTESTAPP ; then execBuildCommand $TESTAPP_NAME "xcodebuild -project \"$KMTESTAPP_PROJECT_PATH\" $BUILD_OPTIONS $BUILD_ACTIONS" fi -### Notarize the app for localdeploy and preprelease ### +### Notarize the app for preprelease ### -if $LOCALDEPLOY || $PREPRELEASE ; then +if $PREPRELEASE || $NOTARIZE; then echo_heading "Notarizing app" if [ "${CODESIGNING_SUPPRESSION}" != "" ] && [ -z "${CERTIFICATE_ID}" ]; then fail "Notarization and signed executable is required for deployment, even locally. Specify CERTIFICATE_ID environment variable for custom certificate."