@@ -29,8 +29,22 @@ struct UTMAppleConfigurationVirtualization: Codable {
29
29
var prettyValue : String {
30
30
switch self {
31
31
case . disabled: return NSLocalizedString ( " Disabled " , comment: " UTMAppleConfigurationDevices " )
32
- case . mouse: return NSLocalizedString ( " Mouse " , comment: " UTMAppleConfigurationDevices " )
33
- case . trackpad: return NSLocalizedString ( " Trackpad " , comment: " UTMAppleConfigurationDevices " )
32
+ case . mouse: return NSLocalizedString ( " Generic Mouse " , comment: " UTMAppleConfigurationDevices " )
33
+ case . trackpad: return NSLocalizedString ( " Mac Trackpad (macOS 13+) " , comment: " UTMAppleConfigurationDevices " )
34
+ }
35
+ }
36
+ }
37
+
38
+ enum KeyboardDevice : String , CaseIterable , QEMUConstant {
39
+ case disabled = " Disabled "
40
+ case generic = " Generic "
41
+ case mac = " Mac "
42
+
43
+ var prettyValue : String {
44
+ switch self {
45
+ case . disabled: return NSLocalizedString ( " Disabled " , comment: " UTMAppleConfigurationDevices " )
46
+ case . generic: return NSLocalizedString ( " Generic USB " , comment: " UTMAppleConfigurationDevices " )
47
+ case . mac: return NSLocalizedString ( " Mac Keyboard (macOS 14+) " , comment: " UTMAppleConfigurationDevices " )
34
48
}
35
49
}
36
50
}
@@ -41,11 +55,9 @@ struct UTMAppleConfigurationVirtualization: Codable {
41
55
42
56
var hasEntropy : Bool = true
43
57
44
- var hasKeyboard : Bool = false
58
+ var keyboard : KeyboardDevice = . disabled
45
59
46
- var hasPointer : Bool = false
47
-
48
- var hasTrackpad : Bool = false
60
+ var pointer : PointerDevice = . disabled
49
61
50
62
var hasRosetta : Bool ?
51
63
@@ -55,8 +67,8 @@ struct UTMAppleConfigurationVirtualization: Codable {
55
67
case hasAudio = " Audio "
56
68
case hasBalloon = " Balloon "
57
69
case hasEntropy = " Entropy "
58
- case hasKeyboard = " Keyboard "
59
- case hasPointer = " Pointer "
70
+ case keyboard = " Keyboard "
71
+ case pointer = " Pointer "
60
72
case hasTrackpad = " Trackpad "
61
73
case rosetta = " Rosetta "
62
74
case hasClipboardSharing = " ClipboardSharing "
@@ -70,13 +82,16 @@ struct UTMAppleConfigurationVirtualization: Codable {
70
82
hasAudio = try values. decode ( Bool . self, forKey: . hasAudio)
71
83
hasBalloon = try values. decode ( Bool . self, forKey: . hasBalloon)
72
84
hasEntropy = try values. decode ( Bool . self, forKey: . hasEntropy)
73
- hasKeyboard = try values. decode ( Bool . self, forKey: . hasKeyboard)
74
- if let legacyPointer = try ? values. decode ( PointerDevice . self, forKey: . hasPointer) {
75
- hasPointer = legacyPointer != . disabled
76
- hasTrackpad = legacyPointer == . trackpad
85
+ if let hasKeyboard = try ? values. decode ( Bool . self, forKey: . keyboard) {
86
+ keyboard = hasKeyboard ? . generic : . disabled
87
+ } else {
88
+ keyboard = try values. decode ( KeyboardDevice . self, forKey: . keyboard)
89
+ }
90
+ if let hasPointer = try ? values. decode ( Bool . self, forKey: . pointer) {
91
+ let hasTrackpad = try values. decodeIfPresent ( Bool . self, forKey: . hasTrackpad) ?? false
92
+ pointer = hasTrackpad ? . trackpad : hasPointer ? . mouse : . disabled
77
93
} else {
78
- hasPointer = try values. decode ( Bool . self, forKey: . hasPointer)
79
- hasTrackpad = try values. decodeIfPresent ( Bool . self, forKey: . hasTrackpad) ?? false
94
+ pointer = try values. decode ( PointerDevice . self, forKey: . pointer)
80
95
}
81
96
if #available( macOS 13 , * ) {
82
97
hasRosetta = try values. decodeIfPresent ( Bool . self, forKey: . rosetta)
@@ -89,9 +104,8 @@ struct UTMAppleConfigurationVirtualization: Codable {
89
104
try container. encode ( hasAudio, forKey: . hasAudio)
90
105
try container. encode ( hasBalloon, forKey: . hasBalloon)
91
106
try container. encode ( hasEntropy, forKey: . hasEntropy)
92
- try container. encode ( hasKeyboard, forKey: . hasKeyboard)
93
- try container. encode ( hasPointer, forKey: . hasPointer)
94
- try container. encode ( hasTrackpad, forKey: . hasTrackpad)
107
+ try container. encode ( keyboard, forKey: . keyboard)
108
+ try container. encode ( pointer, forKey: . pointer)
95
109
try container. encodeIfPresent ( hasRosetta, forKey: . rosetta)
96
110
try container. encode ( hasClipboardSharing, forKey: . hasClipboardSharing)
97
111
}
@@ -108,8 +122,8 @@ extension UTMAppleConfigurationVirtualization {
108
122
hasEntropy = oldConfig. isEntropyEnabled
109
123
if #available( macOS 12 , * ) {
110
124
hasAudio = oldConfig. isAudioEnabled
111
- hasKeyboard = oldConfig. isKeyboardEnabled
112
- hasPointer = oldConfig. isPointingEnabled
125
+ keyboard = oldConfig. isKeyboardEnabled ? . generic : . disabled
126
+ pointer = oldConfig. isPointingEnabled ? . mouse : . disabled
113
127
}
114
128
}
115
129
}
@@ -138,25 +152,25 @@ extension UTMAppleConfigurationVirtualization {
138
152
audioOutputConfiguration. streams = [ audioOutput]
139
153
vzconfig. audioDevices = [ audioInputConfiguration, audioOutputConfiguration]
140
154
}
141
- if hasKeyboard {
155
+ if keyboard != . disabled {
142
156
vzconfig. keyboards = [ VZUSBKeyboardConfiguration ( ) ]
143
157
#if arch(arm64)
144
- if #available( macOS 14 , * ) , isMacOSGuest {
158
+ if #available( macOS 14 , * ) , isMacOSGuest && keyboard == . mac {
145
159
vzconfig. keyboards = [ VZMacKeyboardConfiguration ( ) ]
146
160
}
147
161
#endif
148
162
}
149
- if hasPointer {
163
+ if pointer != . disabled {
150
164
vzconfig. pointingDevices = [ VZUSBScreenCoordinatePointingDeviceConfiguration ( ) ]
151
165
#if arch(arm64)
152
- if #available( macOS 13 , * ) , isMacOSGuest && hasTrackpad {
166
+ if #available( macOS 13 , * ) , isMacOSGuest && pointer == . trackpad {
153
167
// replace with trackpad device
154
168
vzconfig. pointingDevices = [ VZMacTrackpadConfiguration ( ) ]
155
169
}
156
170
#endif
157
171
}
158
172
} else {
159
- if hasAudio || hasKeyboard || hasPointer {
173
+ if hasAudio || keyboard != . disabled || pointer != . disabled {
160
174
throw UTMAppleConfigurationError . featureNotSupported
161
175
}
162
176
}
0 commit comments