mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-06 14:07:32 +00:00
feat(mac): launch config instead of restart
This commit is contained in:
parent
5e2ad19977
commit
75eea02454
7 changed files with 140 additions and 9 deletions
|
|
@ -34,6 +34,18 @@ struct ConfigApp: App {
|
|||
options.releaseName = ConfigAppUtil.versionGitTag
|
||||
options.environment = ConfigAppUtil.sentryEnvironment
|
||||
}
|
||||
|
||||
// get array of arguments passed to binary
|
||||
let arguments = ProcessInfo.processInfo.arguments
|
||||
|
||||
if arguments.contains("--installation") {
|
||||
let installationContainer = _installation.wrappedValue
|
||||
|
||||
// This Task fires on the next run-loop tick after StateObject is allocated
|
||||
Task { @MainActor in
|
||||
installationContainer.executeNewInstall()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
|
|
@ -73,10 +85,10 @@ struct ConfigApp: App {
|
|||
}
|
||||
|
||||
// for testing purposes
|
||||
// Window("Install Test", id: "install-debug") {
|
||||
// InstallDebugView()
|
||||
// .environmentObject(installation)
|
||||
// }
|
||||
Window("Install Test", id: "install-debug") {
|
||||
InstallDebugView()
|
||||
.environmentObject(installation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
import Foundation
|
||||
import KeymanSettings
|
||||
import OSLog
|
||||
import Carbon
|
||||
|
||||
// The data model version number is updated by the input method.
|
||||
// We only read the value here, and if it is current, then there is no need
|
||||
|
|
@ -250,6 +251,15 @@ public class InstallationCheck {
|
|||
name: NSNotification.Name.accessibilityStateResponse,
|
||||
object: nil // Observe notifications from any sender
|
||||
)
|
||||
|
||||
let notificationName = Notification.Name(kTISNotifyEnabledKeyboardInputSourcesChanged as String)
|
||||
DistributedNotificationCenter.default().addObserver(
|
||||
self,
|
||||
selector: #selector(self.handleInputSourcesChanged(_:)),
|
||||
name: notificationName,
|
||||
object: nil // Observe notifications from any sender
|
||||
)
|
||||
|
||||
// TODO: add timeout in case response is not received
|
||||
// see issue #16579
|
||||
}
|
||||
|
|
@ -289,6 +299,61 @@ public class InstallationCheck {
|
|||
Logger.app.debug("handleAccessibilityResponse, received but did not include message")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called when `kTISNotifyEnabledKeyboardInputSourcesChanged` is received
|
||||
*/
|
||||
@objc func handleInputSourcesChanged(_ notification: Notification) {
|
||||
Logger.app.debug("handleKeyboardEnabled received message: \(notification, privacy: .public)")
|
||||
let inputSourceState = self.checkInputSources()
|
||||
}
|
||||
|
||||
public func checkInputSources() -> (registered: Bool, enabled: Bool) {
|
||||
// Correct Carbon filtering keys
|
||||
// let properties = [
|
||||
// kTISPropertyInputSourceCategory: kTISCategoryKeyboardInputSource
|
||||
// ] as CFDictionary
|
||||
var inputSourceState: (registered: Bool, enabled: Bool) = (false, false)
|
||||
|
||||
let inputSourceId = InputMethodUtil.keymanBundleId
|
||||
let properties = [
|
||||
kTISPropertyInputSourceID: inputSourceId as CFString
|
||||
] as CFDictionary
|
||||
|
||||
Logger.app.debug("🚦checking input sources")
|
||||
|
||||
// use includesAllInstalled = true, so we get unregistered input methods
|
||||
guard let listRef = TISCreateInputSourceList(properties, true) else {
|
||||
Logger.app.error("Unable to fetch input source list.")
|
||||
return inputSourceState
|
||||
}
|
||||
|
||||
let inputSourceList = listRef.takeRetainedValue() as! [TISInputSource]
|
||||
|
||||
if (!inputSourceList.isEmpty) {
|
||||
guard let source = inputSourceList.first else {
|
||||
return inputSourceState
|
||||
}
|
||||
|
||||
guard let idPtr = TISGetInputSourceProperty(source, kTISPropertyInputSourceID),
|
||||
let enabledPtr = TISGetInputSourceProperty(source, kTISPropertyInputSourceIsEnabled) else {
|
||||
return inputSourceState
|
||||
}
|
||||
|
||||
inputSourceState.registered = true
|
||||
|
||||
// Extract the string Identifier and boolean Enablement state
|
||||
let sourceID = Unmanaged<CFString>.fromOpaque(idPtr).takeUnretainedValue() as String
|
||||
let isEnabled = Unmanaged<CFBoolean>.fromOpaque(enabledPtr).takeUnretainedValue() as! Bool
|
||||
|
||||
inputSourceState.enabled = isEnabled
|
||||
Logger.app.debug("Source ID: \(sourceID, privacy: .public) | Is Enabled: \(isEnabled)")
|
||||
} else {
|
||||
Logger.app.debug("Keyman input source not registered in system.")
|
||||
}
|
||||
|
||||
return inputSourceState
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the distributed notification message that we received from the Keyman input method.
|
||||
|
|
|
|||
|
|
@ -67,10 +67,34 @@ public class InstallationContainer : ObservableObject {
|
|||
self.confirmUserRestarted()
|
||||
} else {
|
||||
self.registerObservers()
|
||||
self.installationCheck.startInstallationEvaluation()
|
||||
|
||||
// use command line argument to begin installation instead
|
||||
//self.installationCheck.startInstallationEvaluation()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called immediately after startup when invoked from installer post-install script
|
||||
*/
|
||||
func executeNewInstall() {
|
||||
Logger.app.debug("✅ executing new installation...")
|
||||
var didRegister = false
|
||||
var didEnable = false
|
||||
|
||||
// test to see if input method is registered or active
|
||||
let inputSourceState = self.installationCheck.checkInputSources()
|
||||
|
||||
if !inputSourceState.registered {
|
||||
didRegister = self.inputMethodUtil.registerKeymanInputMethod()
|
||||
}
|
||||
|
||||
if !inputSourceState.enabled {
|
||||
didEnable = self.inputMethodUtil.enableKeymanInputMethod()
|
||||
}
|
||||
|
||||
Logger.app.debug("new installation, didRegister: \(didRegister), didEnable: \(didEnable)")
|
||||
}
|
||||
|
||||
/**
|
||||
* register observers to learn of results of InstallationState evaluation
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@
|
|||
},
|
||||
"Install" : {
|
||||
|
||||
},
|
||||
"Install Test" : {
|
||||
|
||||
},
|
||||
"Installation" : {
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ cat <<EOF > "${OUTPUT__DISTRIBUTION_XML}"
|
|||
<choice id="com.keyman.im.installer" visible="false">
|
||||
<pkg-ref id="com.keyman.im.installer"/>
|
||||
</choice>
|
||||
<pkg-ref id="com.keyman.im.installer" version="$KEYMAN_VERSION" onConclusion="RequireRestart">keyman-input-method.pkg</pkg-ref>
|
||||
<pkg-ref id="com.keyman.im.installer" version="$KEYMAN_VERSION" onConclusion="none">keyman-input-method.pkg</pkg-ref>
|
||||
</installer-gui-script>
|
||||
EOF
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
\pard\pardeftab720\partightenfactor0
|
||||
|
||||
\f0\fs26 \cf0 \expnd0\expndtw0\kerning0
|
||||
Restart your Mac, then run
|
||||
Press the Close button.\
|
||||
\
|
||||
|
||||
\f1\b Keyman Configuration
|
||||
\f0\b0 located in the Applications folder to complete setup of Keyman.\
|
||||
\f0\b0 will launch to complete the setup of Keyman.\
|
||||
}
|
||||
|
|
@ -50,7 +50,32 @@ echo "The installer package name is: $PACKAGE_PATH"
|
|||
# define path of tmp file to write keyboard info
|
||||
KEYBOARD_FILE_PATH="$3/var/tmp/keyboard-to-install.txt"
|
||||
|
||||
#write keyboard file
|
||||
# write keyboard file
|
||||
/bin/echo "sil_euro_latin" > "${KEYBOARD_FILE_PATH}"
|
||||
|
||||
# get the Process ID of the parent installer framework that called this script
|
||||
PARENT_PID=$PPID
|
||||
|
||||
# run background process that launches Keyman Configuration app
|
||||
(
|
||||
# # wait up to 15 seconds for the installer processes to completely exit
|
||||
# for i in {1..15}; do
|
||||
# # ps -p checks if the specific parent installer process is still alive.
|
||||
# # If it's dead, ps returns an error code, meaning the installer closed!
|
||||
# if ! ps -p "$PARENT_PID" > /dev/null; then
|
||||
# break
|
||||
# fi
|
||||
# sleep 1
|
||||
# done
|
||||
|
||||
# give the file system a second to commit changes
|
||||
sleep 1
|
||||
|
||||
# check if there is a current user and we are not sitting at the login window, then
|
||||
# launch the Keyman Configuration under the current user with the custom install argument
|
||||
if [ -n "$CONSOLE_USER" ] && [ "$CONSOLE_USER" != "loginwindow" ]; then
|
||||
sudo -u "$CONSOLE_USER" open "/Applications/Keyman Configuration.app" --args --installation
|
||||
fi
|
||||
) &
|
||||
|
||||
exit 0
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue