mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-13 20:25:53 +08:00
[feat] add customizable mobile shortcuts for Windows, macOS and Linux, refs #153
This commit is contained in:
1 parent
72dda9bb90
commit
bad4569117
47 files changed
+3314
-70
No files matched your search
@@ -31,6 +31,7 @@ private enum RemoteKeyboardMetrics {
|
||||
private enum RemoteKeyboardMode: String {
|
||||
case system
|
||||
case computer
|
||||
case shortcuts
|
||||
}
|
||||
|
||||
private struct RemoteViewportState: Equatable {
|
||||
@@ -45,6 +46,10 @@ struct RemoteSessionView: View {
|
||||
@State private var virtualMouseVisible = false
|
||||
@StateObject private var systemKeyboardContext = RemoteKeyboardInputContext()
|
||||
@StateObject private var keyboardGeometry = RemoteKeyboardGeometry()
|
||||
@StateObject private var shortcutStore = RemoteShortcutStore()
|
||||
@State private var shortcutManagerVisible = false
|
||||
@State private var shortcutManagerPlatform = "unknown"
|
||||
@State private var previousKeyboardMode: RemoteKeyboardMode = .computer
|
||||
@State private var keyboardInputVisible = false
|
||||
@State private var keyboardMode: RemoteKeyboardMode = .system
|
||||
@State private var animateSystemKeyboardPresentation = true
|
||||
@@ -171,10 +176,13 @@ struct RemoteSessionView: View {
|
||||
geometry: keyboardGeometry,
|
||||
animatePresentation: animateSystemKeyboardPresentation,
|
||||
didPresent: { waitingForSystemKeyboard = false },
|
||||
shortcuts: shortcutStore.pinned(platform: session.remotePlatform.rawValue),
|
||||
sendShortcut: session.sendShortcut,
|
||||
showShortcuts: { previousKeyboardMode = .shortcuts; keyboardMode = .shortcuts },
|
||||
switchKeyboard: { keyboardMode = .computer },
|
||||
dismiss: { keyboardInputVisible = false })
|
||||
}
|
||||
if keyboardMode == .computer || waitingForSystemKeyboard {
|
||||
if keyboardMode != .system || waitingForSystemKeyboard {
|
||||
dockedKeyboard
|
||||
}
|
||||
}
|
||||
@@ -204,6 +212,7 @@ struct RemoteSessionView: View {
|
||||
if visible {
|
||||
mouseInput.releaseAll()
|
||||
keyboardInputVisible = false
|
||||
shortcutManagerVisible = false
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
@@ -262,6 +271,7 @@ struct RemoteSessionView: View {
|
||||
if !connected {
|
||||
mouseInput.releaseAll()
|
||||
keyboardInputVisible = false
|
||||
shortcutManagerVisible = false
|
||||
}
|
||||
}
|
||||
.onValueChange(of: session.remoteCursorPositionRevision) { _ in
|
||||
@@ -278,6 +288,14 @@ struct RemoteSessionView: View {
|
||||
session.fileImportFailed()
|
||||
}
|
||||
}
|
||||
.fullScreenCover(isPresented: $shortcutManagerVisible, onDismiss: {
|
||||
if session.isConnected && scenePhase == .active && !session.privacyScreen.unlockNotice {
|
||||
keyboardMode = .shortcuts
|
||||
keyboardInputVisible = true
|
||||
}
|
||||
}) {
|
||||
RemoteShortcutManager(store: shortcutStore, platform: shortcutManagerPlatform)
|
||||
}
|
||||
}
|
||||
|
||||
private var privacyUnlockOverlay: some View {
|
||||
@@ -505,7 +523,7 @@ struct RemoteSessionView: View {
|
||||
}
|
||||
}
|
||||
x = min(max(x, halfWidth + 8), max(halfWidth + 8, size.width - halfWidth - 8))
|
||||
if keyboardInputVisible && keyboardMode == .computer {
|
||||
if keyboardInputVisible && keyboardMode != .system {
|
||||
let keyboardSize = keyboardPanelSize(in: size)
|
||||
let center = keyboardCenter(in: size, panelSize: keyboardSize)
|
||||
let keyboardRect = CGRect(x: center.x - keyboardSize.width / 2, y: center.y - keyboardSize.height / 2, width: keyboardSize.width, height: keyboardSize.height)
|
||||
@@ -537,16 +555,33 @@ struct RemoteSessionView: View {
|
||||
.ignoresSafeArea(.keyboard)
|
||||
}
|
||||
|
||||
private func returnToSystemKeyboard() {
|
||||
previousKeyboardMode = keyboardMode
|
||||
animateSystemKeyboardPresentation = false
|
||||
waitingForSystemKeyboard = true
|
||||
keyboardMode = .system
|
||||
}
|
||||
|
||||
private func remoteKeyboardPanel(bottomInset: CGFloat) -> some View {
|
||||
RemoteComputerKeyboard(
|
||||
session: session,
|
||||
switchKeyboard: {
|
||||
animateSystemKeyboardPresentation = false
|
||||
waitingForSystemKeyboard = true
|
||||
keyboardMode = .system
|
||||
},
|
||||
dismiss: { keyboardInputVisible = false }
|
||||
)
|
||||
Group {
|
||||
if keyboardMode == .shortcuts || (waitingForSystemKeyboard && previousKeyboardMode == .shortcuts) {
|
||||
RemoteShortcutPanel(store: shortcutStore, session: session,
|
||||
systemKeyboard: returnToSystemKeyboard,
|
||||
dismiss: { keyboardInputVisible = false },
|
||||
manage: {
|
||||
mouseInput.releaseAll()
|
||||
keyboardInputVisible = false
|
||||
statusMenuVisible = false
|
||||
shortcutManagerPlatform = session.remotePlatform.rawValue
|
||||
shortcutManagerVisible = true
|
||||
})
|
||||
} else {
|
||||
RemoteComputerKeyboard(session: session,
|
||||
switchKeyboard: returnToSystemKeyboard,
|
||||
showShortcuts: { previousKeyboardMode = .shortcuts; keyboardMode = .shortcuts },
|
||||
dismiss: { keyboardInputVisible = false })
|
||||
}
|
||||
}
|
||||
.padding(.bottom, bottomInset)
|
||||
.background(RemoteKeyboardPalette.background)
|
||||
}
|
||||
@@ -837,45 +872,44 @@ private struct RemoteComputerKeyboard: View {
|
||||
@Environment(\.verticalSizeClass) private var verticalSizeClass
|
||||
@StateObject private var feedback = RemoteKeyboardFeedback()
|
||||
let switchKeyboard: () -> Void
|
||||
let showShortcuts: () -> Void
|
||||
let dismiss: () -> Void
|
||||
@State private var activeModifiers: Set<UInt> = []
|
||||
@State private var page: RemoteComputerKeyboardPage = .input
|
||||
|
||||
private static let commonRow: [RemoteComputerKey] = [
|
||||
private var commonRow: [RemoteComputerKey] { [
|
||||
.init("Ctrl", 0x11, isModifier: true),
|
||||
.init("Win", 0x5B, isModifier: true),
|
||||
.init("Alt", 0x12, isModifier: true),
|
||||
.init(RemoteShortcut.modifierName(91, platform: session.remotePlatform.rawValue), 0x5B, isModifier: true),
|
||||
.init(RemoteShortcut.modifierName(18, platform: session.remotePlatform.rawValue), 0x12, isModifier: true),
|
||||
.init(NSLocalizedString("空格", comment: ""), 0x20, width: 2.6),
|
||||
.init(NSLocalizedString("回车", comment: ""), 0x0D, width: 1.4, style: .special)
|
||||
]
|
||||
] }
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
HStack(spacing: 4) {
|
||||
Button(NSLocalizedString("系统键盘", comment: "")) {
|
||||
RemoteKeyboardToolbar(
|
||||
switchKeyboard: {
|
||||
feedback.keyPressed()
|
||||
releaseModifiers()
|
||||
switchKeyboard()
|
||||
}
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.fixedSize(horizontal: true, vertical: false)
|
||||
.frame(minWidth: 80, minHeight: 44)
|
||||
.accessibilityLabel(NSLocalizedString("切换到系统键盘", comment: ""))
|
||||
},
|
||||
more: {
|
||||
releaseModifiers()
|
||||
showShortcuts()
|
||||
},
|
||||
dismiss: {
|
||||
feedback.keyPressed()
|
||||
releaseModifiers()
|
||||
dismiss()
|
||||
},
|
||||
dismissAccessibilityLabel: NSLocalizedString("收起电脑键盘", comment: "")
|
||||
) {
|
||||
if verticalSizeClass == .compact {
|
||||
pageTabs
|
||||
} else {
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
RemoteKeyboardDismissButton(accessibilityLabel: NSLocalizedString("收起电脑键盘", comment: "")) {
|
||||
feedback.keyPressed()
|
||||
releaseModifiers()
|
||||
dismiss()
|
||||
}
|
||||
.frame(width: RemoteKeyboardDismissButton.sideLength,
|
||||
height: RemoteKeyboardDismissButton.sideLength)
|
||||
}
|
||||
.padding(.horizontal, 4)
|
||||
.frame(height: 44)
|
||||
|
||||
if verticalSizeClass != .compact {
|
||||
pageTabs
|
||||
@@ -919,7 +953,7 @@ private struct RemoteComputerKeyboard: View {
|
||||
}
|
||||
|
||||
RemoteComputerKeyboardRow(
|
||||
keys: Self.commonRow,
|
||||
keys: commonRow,
|
||||
activeModifiers: activeModifiers,
|
||||
action: handleKey
|
||||
)
|
||||
@@ -966,14 +1000,13 @@ private struct RemoteComputerKeyboard: View {
|
||||
switch key.action {
|
||||
case let .modifier(keyCode):
|
||||
if activeModifiers.contains(keyCode) {
|
||||
session.sendKeyState(keyCode, isDown: false)
|
||||
activeModifiers.remove(keyCode)
|
||||
} else {
|
||||
session.sendKeyState(keyCode, isDown: true)
|
||||
activeModifiers.insert(keyCode)
|
||||
}
|
||||
case let .stroke(keyCode):
|
||||
session.sendKeyStroke(keyCode)
|
||||
session.sendKeyChord(keyCode, modifiers: Array(activeModifiers))
|
||||
activeModifiers.removeAll()
|
||||
case .switchKeyboard:
|
||||
releaseModifiers()
|
||||
switchKeyboard()
|
||||
@@ -984,9 +1017,6 @@ private struct RemoteComputerKeyboard: View {
|
||||
}
|
||||
|
||||
private func releaseModifiers() {
|
||||
for keyCode in activeModifiers {
|
||||
session.sendKeyState(keyCode, isDown: false)
|
||||
}
|
||||
activeModifiers.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user