From cb67d8b2fa9b9c9d30cd81d72b8737ee2baa44b6 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 19 Jun 2026 14:09:49 +0800
Subject: [PATCH] Fix vertical keyboard window focus

---
 C1.source/Sources/AlignerCore/Windows/QuickSwitchViewModel.swift |   64 ++++++++++++++++++++++++++++++--
 1 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/C1.source/Sources/AlignerCore/Windows/QuickSwitchViewModel.swift b/C1.source/Sources/AlignerCore/Windows/QuickSwitchViewModel.swift
index 1bec9df..18bc70a 100644
--- a/C1.source/Sources/AlignerCore/Windows/QuickSwitchViewModel.swift
+++ b/C1.source/Sources/AlignerCore/Windows/QuickSwitchViewModel.swift
@@ -1,3 +1,4 @@
+import CoreGraphics
 import Foundation
 
 public struct QuickSwitchViewModel: Equatable, Sendable {
@@ -62,6 +63,7 @@
     public let windowCount: Int
     public let appCount: Int
     public let appNames: [String]
+    public let splitViewAppNames: [String]
 
     public init(
         id: UInt64,
@@ -72,7 +74,8 @@
         isCurrent: Bool = false,
         windowCount: Int,
         appCount: Int,
-        appNames: [String] = []
+        appNames: [String] = [],
+        splitViewAppNames: [String] = []
     ) {
         self.id = id
         self.displayUUID = displayUUID
@@ -83,6 +86,7 @@
         self.windowCount = windowCount
         self.appCount = appCount
         self.appNames = appNames
+        self.splitViewAppNames = splitViewAppNames
     }
 }
 
@@ -166,12 +170,14 @@
         let windowCountsBySpace = countWindowsBySpace(windowItems)
         let appCountsBySpace = countAppsBySpace(snapshot.appGroups)
         let appNamesBySpace = appNamesBySpace(snapshot.appGroups)
+        let splitViewAppNamesBySpace = splitViewAppNamesBySpace(snapshot.appGroups)
         let displays = displayViewModels(
             from: snapshot.displays,
             currentSpaceIDs: currentSpaceIDs,
             windowCountsBySpace: windowCountsBySpace,
             appCountsBySpace: appCountsBySpace,
-            appNamesBySpace: appNamesBySpace
+            appNamesBySpace: appNamesBySpace,
+            splitViewAppNamesBySpace: splitViewAppNamesBySpace
         )
         let appShelf = appShelfViewModels(from: snapshot.appGroups)
 
@@ -210,7 +216,8 @@
         currentSpaceIDs: Set<UInt64>,
         windowCountsBySpace: [UInt64: Int],
         appCountsBySpace: [UInt64: Int],
-        appNamesBySpace: [UInt64: [String]]
+        appNamesBySpace: [UInt64: [String]],
+        splitViewAppNamesBySpace: [UInt64: [String]]
     ) -> [QuickSwitchDisplayViewModel] {
         let sortedDisplays = displays
             .sorted { $0.uuid.localizedStandardCompare($1.uuid) == .orderedAscending }
@@ -232,7 +239,8 @@
                             isCurrent: currentSpaceIDs.contains(space.id),
                             windowCount: windowCountsBySpace[space.id] ?? 0,
                             appCount: appCountsBySpace[space.id] ?? 0,
-                            appNames: appNamesBySpace[space.id] ?? []
+                            appNames: appNamesBySpace[space.id] ?? [],
+                            splitViewAppNames: splitViewAppNamesBySpace[space.id] ?? []
                         )
                     }
 
@@ -309,6 +317,54 @@
         return namesBySpace
     }
 
+    private static func splitViewAppNamesBySpace(_ appGroups: [QuickSwitchAppGroup]) -> [UInt64: [String]] {
+        struct Candidate {
+            let appName: String
+            let windowID: UInt32
+            let frame: CGRect
+        }
+
+        var candidatesBySpace: [UInt64: [Candidate]] = [:]
+
+        for group in appGroups {
+            for item in group.windows {
+                guard item.window.isFullscreen,
+                      let primarySpaceID = item.primarySpaceID,
+                      let frame = item.window.frame,
+                      frame.width > 0,
+                      frame.height > 0
+                else {
+                    continue
+                }
+
+                candidatesBySpace[primarySpaceID, default: []].append(
+                    Candidate(
+                        appName: group.app.name,
+                        windowID: item.window.id,
+                        frame: frame
+                    )
+                )
+            }
+        }
+
+        return candidatesBySpace.compactMapValues { candidates in
+            guard candidates.count >= 2 else { return nil }
+
+            return candidates
+                .sorted { lhs, rhs in
+                    if lhs.frame.midX != rhs.frame.midX {
+                        return lhs.frame.midX < rhs.frame.midX
+                    }
+                    if lhs.frame.midY != rhs.frame.midY {
+                        return lhs.frame.midY < rhs.frame.midY
+                    }
+                    return lhs.windowID < rhs.windowID
+                }
+                .prefix(2)
+                .map(\.appName)
+        }
+    }
+
     private static func orderedUnique<T: Hashable>(_ values: [T]) -> [T] {
         var seen = Set<T>()
         var result: [T] = []

--
Gitblit v1.9.3