Files
bsky-social-app/modules/expo-keyboard-language/ios/ExpoKeyboardLanguageModule.swift
T
Samuel Newman d1666345ae auto-detect composer language from keyboard
adds a new expo-keyboard-language native module that reads the current
keyboard language on iOS (via first responder's textInputMode) and
Android (via InputMethodManager). iOS also gets real-time updates when
the keyboard language changes.

users opt in via Settings > Languages > "Automatically detect post
language from keyboard" (native only, marked experimental). when
enabled, the composer language tracks the keyboard language. users can
override per-session by selecting a language manually, and re-enable
auto mode via the "Automatic" item in the language menu.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-28 16:00:45 +02:00

76 lines
1.9 KiB
Swift

import ExpoModulesCore
public class ExpoKeyboardLanguageModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoKeyboardLanguage")
Events("onKeyboardLanguageChange")
Function("getCurrentKeyboardLanguage") {
return self.currentKeyboardLanguage()
}
OnStartObserving {
NotificationCenter.default.addObserver(
self,
selector: #selector(self.onInputModeOrResponderChange),
name: UITextInputMode.currentInputModeDidChangeNotification,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(self.onInputModeOrResponderChange),
name: UIResponder.keyboardDidShowNotification,
object: nil
)
}
OnStopObserving {
NotificationCenter.default.removeObserver(
self,
name: UITextInputMode.currentInputModeDidChangeNotification,
object: nil
)
NotificationCenter.default.removeObserver(
self,
name: UIResponder.keyboardDidShowNotification,
object: nil
)
}
}
private var lastLanguage: String?
@objc
private func onInputModeOrResponderChange() {
let language = currentKeyboardLanguage()
if language != lastLanguage {
lastLanguage = language
sendEvent("onKeyboardLanguageChange", [
"language": language as Any
])
}
}
private func currentKeyboardLanguage() -> String? {
let keyWindow = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.first { $0.isKeyWindow }
return keyWindow?.findFirstResponder()?.textInputMode?.primaryLanguage
}
}
private extension UIView {
func findFirstResponder() -> UIView? {
if isFirstResponder { return self }
for subview in subviews {
if let found = subview.findFirstResponder() {
return found
}
}
return nil
}
}