objc2-game-controller 0.3.2

Bindings to the GameController framework
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
//! This file has been automatically generated by `objc2`'s `header-translator`.
//! DO NOT EDIT
use core::ffi::*;
use core::ptr::NonNull;
use objc2::__framework_prelude::*;
use objc2_foundation::*;

use crate::*;

extern "C" {
    /// Use these constants with NSNotificationCenter to listen to connection and disconnection events.
    ///
    /// Use GCControllerDidConnectNotification for observing connections of controllers.
    /// Use GCControllerDidDisconnectNotification for observing disconnections of controllers.
    ///
    /// Connections and disconnections of controllers will also be reflected in the controllers array
    /// of the GCController class.
    ///
    /// The 'object' property of the notification will contain the GCController that was connected or disconnected.
    /// For example:
    ///
    /// - (void)controllerDidConnect:(NSNotification *)note {
    ///
    /// GCController *controller = note.object;
    ///
    /// ....
    /// }
    ///
    ///
    /// See: NSNotificationCenter
    ///
    /// See: GCController.controllers
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/gamecontroller/gccontrollerdidconnectnotification?language=objc)
    pub static GCControllerDidConnectNotification: &'static NSString;
}

extern "C" {
    /// [Apple's documentation](https://developer.apple.com/documentation/gamecontroller/gccontrollerdiddisconnectnotification?language=objc)
    pub static GCControllerDidDisconnectNotification: &'static NSString;
}

extern "C" {
    /// Use these constants with NSNotificationCenter to listen to a controller becoming the most recently used controller.
    /// This is a good time to swap out UI to match the new current controller, and unregister any handlers with
    /// the old current controller.
    ///
    /// The 'object' property of the notification will contain the GCController that became the current controller.
    /// For example:
    ///
    /// - (void)controllerDidBecomeCurrent:(NSNotification *)note {
    ///
    /// GCController *controller = note.object;
    ///
    /// ...
    /// }
    ///
    /// See: NSNotificationCenter
    ///
    /// See: GCController.controllers
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/gamecontroller/gccontrollerdidbecomecurrentnotification?language=objc)
    pub static GCControllerDidBecomeCurrentNotification: &'static NSString;
}

extern "C" {
    /// [Apple's documentation](https://developer.apple.com/documentation/gamecontroller/gccontrollerdidstopbeingcurrentnotification?language=objc)
    pub static GCControllerDidStopBeingCurrentNotification: &'static NSString;
}

extern "C" {
    /// Use this constant with NSNotificationCenter to listen to controller user customization events.
    ///
    /// When a user customizes the button mappings or other settings of a controller this notification will be
    /// posted. This is a good time to swap out UI to match the new user settings. Users can modify game
    /// controller settings through the Settings app on iOS, tvOS, and macOS.
    ///
    /// The 'object' property of the notification will contain the GCController that was customized.
    /// For example:
    ///
    /// - (void)controllerDidConnect:(NSNotification *)note {
    ///
    /// GCController *controller = note.object;
    ///
    /// ....
    /// }
    ///
    ///
    /// See: NSNotificationCenter
    ///
    /// See: GCController.controllers
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/gamecontroller/gccontrollerusercustomizationsdidchangenotification?language=objc)
    pub static GCControllerUserCustomizationsDidChangeNotification: &'static NSString;
}

/// This is the player index that a connected controller will have if it has never been assigned a player index on the current system.
/// Controllers retain the player index they have been assigned between game sessions, so if you wish to unset the player index of a
/// controller set it back to this value.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/gamecontroller/gccontrollerplayerindex?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct GCControllerPlayerIndex(pub NSInteger);
impl GCControllerPlayerIndex {
    #[doc(alias = "GCControllerPlayerIndexUnset")]
    pub const IndexUnset: Self = Self(-1);
    #[doc(alias = "GCControllerPlayerIndex1")]
    pub const Index1: Self = Self(0);
    #[doc(alias = "GCControllerPlayerIndex2")]
    pub const Index2: Self = Self(1);
    #[doc(alias = "GCControllerPlayerIndex3")]
    pub const Index3: Self = Self(2);
    #[doc(alias = "GCControllerPlayerIndex4")]
    pub const Index4: Self = Self(3);
}

unsafe impl Encode for GCControllerPlayerIndex {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

unsafe impl RefEncode for GCControllerPlayerIndex {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

extern_class!(
    /// Controllers are available to an application that links to GameController.framework. There are 2 ways to access controllers
    /// paired to the system, adopt both to ensure the best user experience:
    ///
    /// 1: Querying for the the current array or controllers using [GCController controllers].
    /// 2: Registering for Connection/Disconnection notifications from NSNotificationCenter.
    ///
    /// Only controllers that support one of the allowed profiles, such as GCExtendedGamepad, will be enumerated. Check for the profile
    /// supported before using a controller in your application. Ignore a controller that doesn't support a profile that suits
    /// your application, as the user will expect their controller to either be fully supported or not supported at all.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/gamecontroller/gccontroller?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct GCController;
);

#[cfg(feature = "GCDevice")]
extern_conformance!(
    unsafe impl GCDevice for GCController {}
);

extern_conformance!(
    unsafe impl NSObjectProtocol for GCController {}
);

impl GCController {
    extern_methods!(
        /// Get a list of controllers currently attached to the system.
        ///
        ///
        /// See: GCControllerDidConnectNotification
        ///
        /// See: GCControllerDidDisconnectNotification
        #[unsafe(method(controllers))]
        #[unsafe(method_family = none)]
        pub unsafe fn controllers() -> Retained<NSArray<GCController>>;

        /// The most recently used game controller. If a user actuates a game controller
        /// input, that controller will become the current one.
        ///
        ///
        /// Note: This is useful for single player games where you only care about whether an
        /// input is pressed, and not where it came from.  You will still need to
        /// register for changes to GCController.current so that your UI can remain
        /// up-to-date with the current controller.
        #[unsafe(method(current))]
        #[unsafe(method_family = none)]
        pub unsafe fn current() -> Option<Retained<GCController>>;

        #[cfg(feature = "block2")]
        /// Set this block to be notified when a user intends to suspend or resume the current game state. A controller will have a button
        /// dedicated to suspending and resuming play and invoking context sensitive actions. During event handling the system will
        /// notify the application using this block such that the application can handle the suspension and resumption from the given controller.
        ///
        /// Use this to implement your canonical transition to a pause menu for example if that is your application's desired handling
        /// of suspension in play. You may pause and resume based on game state as well so the event is only called each time the
        /// pause/resume button is pressed.
        ///
        ///
        /// Note: This handler has been deprecated in favor of the Menu button found on GCMicroGamepad and GCExtendedGamepad.
        ///
        /// See: microGamepad
        ///
        /// See: extendedGamepad
        ///
        /// # Safety
        ///
        /// The returned block's argument must be a valid pointer.
        #[deprecated = "Use the Menu button found on the controller's input profile, if it exists."]
        #[unsafe(method(controllerPausedHandler))]
        #[unsafe(method_family = none)]
        pub unsafe fn controllerPausedHandler(
            &self,
        ) -> *mut block2::DynBlock<dyn Fn(NonNull<GCController>)>;

        #[cfg(feature = "block2")]
        /// Setter for [`controllerPausedHandler`][Self::controllerPausedHandler].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[deprecated = "Use the Menu button found on the controller's input profile, if it exists."]
        #[unsafe(method(setControllerPausedHandler:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setControllerPausedHandler(
            &self,
            controller_paused_handler: Option<&block2::DynBlock<dyn Fn(NonNull<GCController>)>>,
        );

        /// Whether the current application should monitor and respond to game controller events when it is not the frontmost application.
        ///
        ///
        /// not be forwarded to the application. Once the application becomes the frontmost application, game controller events will be forwarded.
        ///
        ///
        /// Note: Starting with macOS Big Sur 11.3, shouldMonitorBackgroundEvents will be NO by default. For applications built prior to macOS Big Sur 11.3,
        /// (or running on devices with an earlier version of macOS), shouldMonitorBackgroundEvents will be YES by default. On iOS and tvOS, this property is ignored.
        #[unsafe(method(shouldMonitorBackgroundEvents))]
        #[unsafe(method_family = none)]
        pub unsafe fn shouldMonitorBackgroundEvents() -> bool;

        /// Setter for [`shouldMonitorBackgroundEvents`][Self::shouldMonitorBackgroundEvents].
        #[unsafe(method(setShouldMonitorBackgroundEvents:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setShouldMonitorBackgroundEvents(should_monitor_background_events: bool);

        /// A controller may be form fitting or otherwise closely attached to the device. This closeness to other inputs on the device
        /// may suggest that interaction with the device may use other inputs easily. This is presented to developers to allow them to
        /// make informed decisions about UI and interactions to choose for their game in this situation.
        #[unsafe(method(isAttachedToDevice))]
        #[unsafe(method_family = none)]
        pub unsafe fn isAttachedToDevice(&self) -> bool;

        /// A player index for the controller, defaults to GCControllerPlayerIndexUnset.
        ///
        /// This can be set both for the application to keep track of controllers and as a signal to make a controller display a player
        /// index on a set of LEDs or some other mechanism.
        ///
        /// A controller is not guaranteed to have a visual display of the playerIndex, playerIndex does not persist for a controller
        /// with regards to a system.
        ///
        /// Negative values less than GCControllerPlayerIndexUnset will just map back to GCControllerPlayerIndexUnset when read back.
        #[unsafe(method(playerIndex))]
        #[unsafe(method_family = none)]
        pub unsafe fn playerIndex(&self) -> GCControllerPlayerIndex;

        /// Setter for [`playerIndex`][Self::playerIndex].
        #[unsafe(method(setPlayerIndex:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setPlayerIndex(&self, player_index: GCControllerPlayerIndex);

        #[cfg(feature = "GCControllerInput")]
        /// Gets the input profile for the controller.
        #[unsafe(method(input))]
        #[unsafe(method_family = none)]
        pub unsafe fn input(&self) -> Retained<GCControllerLiveInput>;

        #[cfg(feature = "GCDeviceBattery")]
        /// Gets the battery information if controller supports one
        ///
        /// This property is useful when you try to notify your user to change or charge controller before it runs out of battery life
        /// or simply display the current battery level and status.
        #[unsafe(method(battery))]
        #[unsafe(method_family = none)]
        pub unsafe fn battery(&self) -> Option<Retained<GCDeviceBattery>>;

        #[cfg(feature = "GCPhysicalInputProfile")]
        /// Gets the physical input profile for the controller.
        ///
        ///
        /// Note: This is equivalent to the controller's microGamepad, or extendedGamepad instance.
        ///
        /// See: microGamepad
        ///
        /// See: extendedGamepad
        #[unsafe(method(physicalInputProfile))]
        #[unsafe(method_family = none)]
        pub unsafe fn physicalInputProfile(&self) -> Retained<GCPhysicalInputProfile>;

        #[cfg(all(feature = "GCGamepad", feature = "GCPhysicalInputProfile"))]
        /// Gets the profile for the controller that suits current application.
        ///
        /// There are several supported profiles, with an additional optional profile for motion as well.
        /// Each controller may be able to map its inputs into all profiles or just one kind of profile. Query for the controller
        /// profile that suits your game, the simplest kind will be supported by the broadest variety
        /// of controllers. A controller supporting the Extended Gamepad profile for example supports the Gamepad profile and more.
        /// As such it can always be used just in the Gamepad profile if that suits the game.
        ///
        /// A physical controller that supports a profile must support it completely. That means that all buttons and axis inputs must
        /// be valid inputs that a developer can utilize.
        ///
        /// If a controller does not support the given profile the returned value will be nil. Use this to filter controllers if the
        /// application requires a specific kind of profile.
        ///
        /// See: motion
        #[deprecated]
        #[unsafe(method(gamepad))]
        #[unsafe(method_family = none)]
        pub unsafe fn gamepad(&self) -> Option<Retained<GCGamepad>>;

        #[cfg(all(feature = "GCMicroGamepad", feature = "GCPhysicalInputProfile"))]
        #[unsafe(method(microGamepad))]
        #[unsafe(method_family = none)]
        pub unsafe fn microGamepad(&self) -> Option<Retained<GCMicroGamepad>>;

        #[cfg(all(feature = "GCExtendedGamepad", feature = "GCPhysicalInputProfile"))]
        #[unsafe(method(extendedGamepad))]
        #[unsafe(method_family = none)]
        pub unsafe fn extendedGamepad(&self) -> Option<Retained<GCExtendedGamepad>>;

        #[cfg(feature = "GCMotion")]
        /// Gets the motion input profile. This profile is optional and may be available if the controller is attached to a device that supports motion.
        /// If this is nil the controller does not support motion input and only the gamepad
        /// &
        /// extendedGamepad profiles are available.
        ///
        /// See: gamepad
        ///
        /// See: extendedGamepad
        #[unsafe(method(motion))]
        #[unsafe(method_family = none)]
        pub unsafe fn motion(&self) -> Option<Retained<GCMotion>>;

        #[cfg(feature = "GCDeviceLight")]
        /// Gets the light for the controller, if one exists.
        ///
        /// A controller's light can be used to signal information to the player, such as using different light colors based on the player
        /// index. It can also be used to react to in-game events and enhance user immersion.
        #[unsafe(method(light))]
        #[unsafe(method_family = none)]
        pub unsafe fn light(&self) -> Option<Retained<GCDeviceLight>>;

        #[cfg(feature = "GCDeviceHaptics")]
        /// Gets the haptics for the controller, if one exists.
        ///
        /// Use this property to create CHHapticEngine instances according to your needs.
        ///
        ///
        /// Note: Haptics are a drain on the controller's battery, and can be distracting when used excessively.
        #[unsafe(method(haptics))]
        #[unsafe(method_family = none)]
        pub unsafe fn haptics(&self) -> Option<Retained<GCDeviceHaptics>>;
    );
}

/// Methods declared on superclass `NSObject`.
impl GCController {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;
    );
}

/// Snapshot.
impl GCController {
    extern_methods!(
        /// A controller may represent a real device managed by the operating system,
        /// or a virtual snapshot created by the developer.  If a controller is created
        /// by the developer, it is considered to be a snapshot, allowing direct writes
        /// to any GCControllerElement of its profiles.  If the controller is not
        /// snapshot, the system will reject any write requests to GCControllerElement.
        ///
        ///
        /// See: controllerWithMicroGamepad
        ///
        /// See: controllerWithExtendedGamepad
        ///
        /// See: capture
        #[unsafe(method(isSnapshot))]
        #[unsafe(method_family = none)]
        pub unsafe fn isSnapshot(&self) -> bool;

        /// Polls the state vector of the controller and saves it to a new and writable
        /// instance of GCController.
        ///
        /// If your application is heavily multithreaded this may also be useful to
        /// guarantee atomicity of input handling as a snapshot will not change based
        /// on user input once it is taken.
        ///
        ///
        /// See: snapshot
        ///
        /// Returns: A new controller with the duplicated state vector of the current
        /// controller.
        #[unsafe(method(capture))]
        #[unsafe(method_family = none)]
        pub unsafe fn capture(&self) -> Retained<GCController>;

        /// Creates a controller with a micro gamepad profile.
        ///
        /// This controller will be considered a snapshot, allowing developers to write
        /// to any GCControllerElement of its profiles.
        ///
        ///
        /// See: snapshot
        ///
        /// Returns: A new controller with a micro gamepad profile
        #[unsafe(method(controllerWithMicroGamepad))]
        #[unsafe(method_family = none)]
        pub unsafe fn controllerWithMicroGamepad() -> Retained<GCController>;

        /// Creates a controller with an extended gamepad profile.
        ///
        /// This controller will be considered a snapshot, allowing developers to write to any GCControllerElement of its profiles.
        ///
        ///
        /// See: snapshot
        ///
        /// Returns: A new controller with an extended gamepad profile
        #[unsafe(method(controllerWithExtendedGamepad))]
        #[unsafe(method_family = none)]
        pub unsafe fn controllerWithExtendedGamepad() -> Retained<GCController>;
    );
}

/// Discovery.
impl GCController {
    extern_methods!(
        #[cfg(feature = "block2")]
        /// Start discovery of new wireless controllers that are discoverable. This is an asynchronous and the supplied completionHandler
        /// will get called once no more devices can be found. If there are already multiple controllers available for use, there
        /// may be little reason to automatically start discovery of new wireless controllers. In this situation it may be best to
        /// allow the user to start discovery manually via in-game UI.
        ///
        /// Once discovery has started new controllers will notify themselves as connected via GCControllerDidConnectNotification.
        /// As the notification arrives the controller is also available in the controllers array.
        ///
        /// The completionHandler could be used to update UI and/or game state to indicate that no more controllers will be found
        /// and the current set of controllers is what is available for use in the game.
        ///
        /// If a completionHandler was provided, it will be called once when discovery stops. Either from an explicit call to
        /// stopWirelessControllerDiscovery or from timing out or stopping in its natural course of operation. Thus the
        /// completionHandler will at most be called once per call to startWirelessControllerDiscoveryWithCompletionHandler:.
        ///
        /// The completionHandler may also not get called at all, if for example startWirelessControllerDiscoveryWithCompletionHandler:
        /// is called multiple times during dicovery. For this case the net effect is that the completionHandler is replaced with each call
        /// and only the last one set before discovery stops will be called.
        ///
        ///
        /// Parameter `completionHandler`: an optional handler that is called when discovery stops. (may be nil, in which case you will not be notified when discovery stops)
        ///
        /// See: stopWirelessControllerDiscovery
        ///
        /// See: controllers
        #[unsafe(method(startWirelessControllerDiscoveryWithCompletionHandler:))]
        #[unsafe(method_family = none)]
        pub unsafe fn startWirelessControllerDiscoveryWithCompletionHandler(
            completion_handler: Option<&block2::DynBlock<dyn Fn()>>,
        );

        /// If no more controllers are needed, depending on game state or number of controllers supported by a game, the discovery
        /// process can be stopped. Calling stopWirelessControllerDiscovery when no discovery is currently in progress will return
        /// immediately without any effect, thus it is safe to call even if the completionHandler of
        /// startWirelessControllerDiscoveryWithCompletionHandler: has been called.
        ///
        ///
        /// See: startWirelessControllerDiscoveryWithCompletionHandler:
        #[unsafe(method(stopWirelessControllerDiscovery))]
        #[unsafe(method_family = none)]
        pub unsafe fn stopWirelessControllerDiscovery();
    );
}