ObjFW  Check-in [e01b5123f1]

Overview
Comment:ObjFWHID: Add support for Nintendo Switch
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e01b5123f1c324c4d94a67358afdee67cf08a928443ad120062ccc4e02376fab
User & Date: js on 2024-06-09 23:24:57
Other Links: manifest | tags
References
2024-06-09
23:41 Fixed ticket [0227cda045]: Support `OHGameController` on Nintendo Switch plus 4 other changes artifact: fe4867c5dc user: js
Context
2024-06-09
23:39
Various cleanups check-in: 01f1d066bc user: js tags: trunk
23:24
ObjFWHID: Add support for Nintendo Switch check-in: e01b5123f1 user: js tags: trunk
17:25
Fix build on Windows check-in: 80f3a121e5 user: js tags: trunk
Changes

Modified .fossil-settings/ignore-glob from [3a81b89ba8] to [5ea8078660].

45
46
47
48
49
50
51

52
53
54
55
56
57
58
tests/big_dictionary_msgpack_gz.m
tests/boot.dol
tests/gamecontroller/boot.dol
tests/gamecontroller/tests
tests/gamecontroller/tests.3dsx
tests/gamecontroller/tests.arm9
tests/gamecontroller/tests.nds

tests/iOS.xcodeproj/*.pbxuser
tests/iOS.xcodeproj/project.xcworkspace
tests/iOS.xcodeproj/xcuserdata
tests/objc_sync/objc_sync
tests/plugin/Info.plist
tests/subprocess/subprocess
tests/terminal/terminal_tests







>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
tests/big_dictionary_msgpack_gz.m
tests/boot.dol
tests/gamecontroller/boot.dol
tests/gamecontroller/tests
tests/gamecontroller/tests.3dsx
tests/gamecontroller/tests.arm9
tests/gamecontroller/tests.nds
tests/gamecontroller/tests.nro
tests/iOS.xcodeproj/*.pbxuser
tests/iOS.xcodeproj/project.xcworkspace
tests/iOS.xcodeproj/xcuserdata
tests/objc_sync/objc_sync
tests/plugin/Info.plist
tests/subprocess/subprocess
tests/terminal/terminal_tests

Modified configure.ac from [9cf24819d0] to [da5b98bd30].

283
284
285
286
287
288
289

290
291
292
293
294
295
296
	enable_shared="no"
	enable_threads="yes"
	enable_sockets="no"	# TODO
	check_pedantic="no"

	AC_DEFINE(OF_NINTENDO_SWITCH, 1,
		[Whether we are compiling for Nintendo Switch])

])

CPP="$OBJCPP"
CPPFLAGS="$CPPFLAGS $OBJCPPFLAGS -DOF_COMPILING_OBJFW"
flags="-fexceptions -fobjc-exceptions -funwind-tables"
flags="$flags -fconstant-string-class=OFConstantString"
OBJCFLAGS="$OBJCFLAGS -Wall $flags"







>







283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
	enable_shared="no"
	enable_threads="yes"
	enable_sockets="no"	# TODO
	check_pedantic="no"

	AC_DEFINE(OF_NINTENDO_SWITCH, 1,
		[Whether we are compiling for Nintendo Switch])
	AC_SUBST(USE_SRCS_NINTENDO_SWITCH, '${SRCS_NINTENDO_SWITCH}')
])

CPP="$OBJCPP"
CPPFLAGS="$CPPFLAGS $OBJCPPFLAGS -DOF_COMPILING_OBJFW"
flags="-fexceptions -fobjc-exceptions -funwind-tables"
flags="$flags -fconstant-string-class=OFConstantString"
OBJCFLAGS="$OBJCFLAGS -Wall $flags"

Modified extra.mk.in from [9f19d25a21] to [fce4ff237a].

98
99
100
101
102
103
104

105
106
107
108
109
110
111
USE_INCLUDES_ATOMIC = @USE_INCLUDES_ATOMIC@
USE_SRCS_APPLETALK = @USE_SRCS_APPLETALK@
USE_SRCS_EVDEV = @USE_SRCS_EVDEV@
USE_SRCS_FILES = @USE_SRCS_FILES@
USE_SRCS_IPX = @USE_SRCS_IPX@
USE_SRCS_NINTENDO_3DS = @USE_SRCS_NINTENDO_3DS@
USE_SRCS_NINTENDO_DS = @USE_SRCS_NINTENDO_DS@

USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@
USE_SRCS_SCTP = @USE_SRCS_SCTP@
USE_SRCS_SOCKETS = @USE_SRCS_SOCKETS@
USE_SRCS_SUBPROCESSES = @USE_SRCS_SUBPROCESSES@
USE_SRCS_TAGGED_POINTERS = @USE_SRCS_TAGGED_POINTERS@
USE_SRCS_THREADS = @USE_SRCS_THREADS@
USE_SRCS_UNIX_SOCKETS = @USE_SRCS_UNIX_SOCKETS@







>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
USE_INCLUDES_ATOMIC = @USE_INCLUDES_ATOMIC@
USE_SRCS_APPLETALK = @USE_SRCS_APPLETALK@
USE_SRCS_EVDEV = @USE_SRCS_EVDEV@
USE_SRCS_FILES = @USE_SRCS_FILES@
USE_SRCS_IPX = @USE_SRCS_IPX@
USE_SRCS_NINTENDO_3DS = @USE_SRCS_NINTENDO_3DS@
USE_SRCS_NINTENDO_DS = @USE_SRCS_NINTENDO_DS@
USE_SRCS_NINTENDO_SWITCH = @USE_SRCS_NINTENDO_SWITCH@
USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@
USE_SRCS_SCTP = @USE_SRCS_SCTP@
USE_SRCS_SOCKETS = @USE_SRCS_SOCKETS@
USE_SRCS_SUBPROCESSES = @USE_SRCS_SUBPROCESSES@
USE_SRCS_TAGGED_POINTERS = @USE_SRCS_TAGGED_POINTERS@
USE_SRCS_THREADS = @USE_SRCS_THREADS@
USE_SRCS_UNIX_SOCKETS = @USE_SRCS_UNIX_SOCKETS@

Modified src/hid/Makefile from [b9d799174b] to [1c32c733a0].

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
       OHGameControllerAxis.m		\
       OHGameControllerButton.m		\
       OHGameControllerDirectionalPad.m	\
       OHGameControllerElement.m	\
       ${USE_SRCS_EVDEV}		\
       ${USE_SRCS_NINTENDO_3DS}		\
       ${USE_SRCS_NINTENDO_DS}		\

       ${USE_SRCS_WII}			\
       ${USE_SRCS_XINPUT}
SRCS_EVDEV = OHEvdevDualSense.m				\
	     OHEvdevDualShock4.m			\
	     OHEvdevExtendedGamepad.m			\
	     OHEvdevGameController.m			\
	     OHEvdevPlayStationExtendedGamepad.m	\
	     OHEvdevStadiaExtendedGamepad.m
SRCS_NINTENDO_3DS = OHNintendo3DSExtendedGamepad.m	\
		    OHNintendo3DSGameController.m
SRCS_NINTENDO_DS = OHNintendoDSGamepad.m	\
		   OHNintendoDSGameController.m


SRCS_WII = OHWiiClassicController.m	\
	   OHWiiGameController.m
SRCS_XINPUT = OHXInputExtendedGamepad.m	\
	      OHXInputGameController.m

INCLUDES := ${SRCS:.m=.h}		\
	    OHExtendedGamepad.h		\







>












>
>







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
       OHGameControllerAxis.m		\
       OHGameControllerButton.m		\
       OHGameControllerDirectionalPad.m	\
       OHGameControllerElement.m	\
       ${USE_SRCS_EVDEV}		\
       ${USE_SRCS_NINTENDO_3DS}		\
       ${USE_SRCS_NINTENDO_DS}		\
       ${USE_SRCS_NINTENDO_SWITCH}	\
       ${USE_SRCS_WII}			\
       ${USE_SRCS_XINPUT}
SRCS_EVDEV = OHEvdevDualSense.m				\
	     OHEvdevDualShock4.m			\
	     OHEvdevExtendedGamepad.m			\
	     OHEvdevGameController.m			\
	     OHEvdevPlayStationExtendedGamepad.m	\
	     OHEvdevStadiaExtendedGamepad.m
SRCS_NINTENDO_3DS = OHNintendo3DSExtendedGamepad.m	\
		    OHNintendo3DSGameController.m
SRCS_NINTENDO_DS = OHNintendoDSGamepad.m	\
		   OHNintendoDSGameController.m
SRCS_NINTENDO_SWITCH = OHNintendoSwitchExtendedGamepad.m	\
		       OHNintendoSwitchGameController.m
SRCS_WII = OHWiiClassicController.m	\
	   OHWiiGameController.m
SRCS_XINPUT = OHXInputExtendedGamepad.m	\
	      OHXInputGameController.m

INCLUDES := ${SRCS:.m=.h}		\
	    OHExtendedGamepad.h		\

Modified src/hid/OHGameController.m from [9eedd672bc] to [f031e78d5e].

35
36
37
38
39
40
41



42
43
44
45
46
47
48
#endif
#ifdef OF_NINTENDO_3DS
# import "OHNintendo3DSGameController.h"
#endif
#ifdef OF_WII
# import "OHWiiGameController.h"
#endif




const uint16_t OHVendorIDSony = 0x054C;
const uint16_t OHVendorIDNintendo = 0x057E;
const uint16_t OHVendorIDGoogle = 0x18D1;
const uint16_t OHProductIDDualShock4 = 0x09CC;
const uint16_t OHProductIDDualSense = 0x0CE6;
const uint16_t OHProductIDLeftJoyCon = 0x2006;







>
>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#endif
#ifdef OF_NINTENDO_3DS
# import "OHNintendo3DSGameController.h"
#endif
#ifdef OF_WII
# import "OHWiiGameController.h"
#endif
#ifdef OF_NINTENDO_SWITCH
# import "OHNintendoSwitchGameController.h"
#endif

const uint16_t OHVendorIDSony = 0x054C;
const uint16_t OHVendorIDNintendo = 0x057E;
const uint16_t OHVendorIDGoogle = 0x18D1;
const uint16_t OHProductIDDualShock4 = 0x09CC;
const uint16_t OHProductIDDualSense = 0x0CE6;
const uint16_t OHProductIDLeftJoyCon = 0x2006;
61
62
63
64
65
66
67


68
69
70
71
72
73
74
	return [OHXInputGameController controllers];
#elif defined(OF_NINTENDO_DS)
	return [OHNintendoDSGameController controllers];
#elif defined(OF_NINTENDO_3DS)
	return [OHNintendo3DSGameController controllers];
#elif defined(OF_WII)
	return [OHWiiGameController controllers];


#else
	return [OFArray array];
#endif
}

- (instancetype)init
{







>
>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
	return [OHXInputGameController controllers];
#elif defined(OF_NINTENDO_DS)
	return [OHNintendoDSGameController controllers];
#elif defined(OF_NINTENDO_3DS)
	return [OHNintendo3DSGameController controllers];
#elif defined(OF_WII)
	return [OHWiiGameController controllers];
#elif defined(OF_NINTENDO_SWITCH)
	return [OHNintendoSwitchGameController controllers];
#else
	return [OFArray array];
#endif
}

- (instancetype)init
{

Added src/hid/OHNintendoSwitchExtendedGamepad.h version [506fd309d9].

































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3.0 only,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * version 3.0 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3.0 along with this program. If not, see
 * <https://www.gnu.org/licenses/>.
 */

#import "OHExtendedGamepad.h"

OF_ASSUME_NONNULL_BEGIN

@interface OHNintendoSwitchExtendedGamepad: OFObject <OHExtendedGamepad>
{
	OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *) *_buttons;
	OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *)
	    *_directionalPads;
}
@end

OF_ASSUME_NONNULL_END

Added src/hid/OHNintendoSwitchExtendedGamepad.m version [472015d4b9].

























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3.0 only,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * version 3.0 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3.0 along with this program. If not, see
 * <https://www.gnu.org/licenses/>.
 */

#include "config.h"

#import "OHNintendoSwitchExtendedGamepad.h"
#import "OFDictionary.h"
#import "OHGameControllerAxis.h"
#import "OHGameControllerButton.h"
#import "OHGameControllerDirectionalPad.h"

static OFString *const buttonNames[] = {
	@"A", @"B", @"X", @"Y", @"L", @"R", @"ZL", @"ZR", @"Left Thumbstick",
	@"Right Thumbstick", @"+", @"-"
};
static const size_t numButtons = sizeof(buttonNames) / sizeof(*buttonNames);

@implementation OHNintendoSwitchExtendedGamepad
@synthesize buttons = _buttons, directionalPads = _directionalPads;

- (instancetype)init
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();
		OFMutableDictionary *buttons =
		    [OFMutableDictionary dictionaryWithCapacity: numButtons];
		OFMutableDictionary *directionalPads;
		OHGameControllerAxis *xAxis, *yAxis;
		OHGameControllerDirectionalPad *directionalPad;
		OHGameControllerButton *up, *down, *left, *right;

		for (size_t i = 0; i < numButtons; i++) {
			OHGameControllerButton *button =
			    [[[OHGameControllerButton alloc]
			    initWithName: buttonNames[i]] autorelease];
			[buttons setObject: button forKey: buttonNames[i]];
		}
		[buttons makeImmutable];
		_buttons = [buttons retain];

		directionalPads =
		    [OFMutableDictionary dictionaryWithCapacity: 3];

		xAxis = [[[OHGameControllerAxis alloc]
		    initWithName: @"X"] autorelease];
		yAxis = [[[OHGameControllerAxis alloc]
		    initWithName: @"Y"] autorelease];
		directionalPad = [[[OHGameControllerDirectionalPad alloc]
		    initWithName: @"Left Thumbstick"
			   xAxis: xAxis
			   yAxis: yAxis] autorelease];
		[directionalPads setObject: directionalPad
				    forKey: @"Left Thumbstick"];

		xAxis = [[[OHGameControllerAxis alloc]
		    initWithName: @"RX"] autorelease];
		yAxis = [[[OHGameControllerAxis alloc]
		    initWithName: @"RY"] autorelease];
		directionalPad = [[[OHGameControllerDirectionalPad alloc]
		    initWithName: @"Right Thumbstick"
			   xAxis: xAxis
			   yAxis: yAxis] autorelease];
		[directionalPads setObject: directionalPad
				    forKey: @"Right Thumbstick"];

		up = [[[OHGameControllerButton alloc]
		    initWithName: @"D-Pad Up"] autorelease];
		down = [[[OHGameControllerButton alloc]
		    initWithName: @"D-Pad Down"] autorelease];
		left = [[[OHGameControllerButton alloc]
		    initWithName: @"D-Pad Left"] autorelease];
		right = [[[OHGameControllerButton alloc]
		    initWithName: @"D-Pad Right"] autorelease];
		directionalPad = [[[OHGameControllerDirectionalPad alloc]
		    initWithName: @"D-Pad"
			      up: up
			    down: down
			    left: left
			   right: right] autorelease];
		[directionalPads setObject: directionalPad forKey: @"D-Pad"];

		[directionalPads makeImmutable];
		_directionalPads = [directionalPads retain];

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_buttons release];
	[_directionalPads release];

	[super dealloc];
}

- (OFDictionary OF_GENERIC(OFString *, OHGameControllerAxis *) *)axes
{
	return [OFDictionary dictionary];
}

- (OHGameControllerButton *)northButton
{
	return [_buttons objectForKey: @"X"];
}

- (OHGameControllerButton *)southButton
{
	return [_buttons objectForKey: @"B"];
}

- (OHGameControllerButton *)westButton
{
	return [_buttons objectForKey: @"Y"];
}

- (OHGameControllerButton *)eastButton
{
	return [_buttons objectForKey: @"A"];
}

- (OHGameControllerButton *)leftShoulderButton
{
	return [_buttons objectForKey: @"L"];
}

- (OHGameControllerButton *)rightShoulderButton
{
	return [_buttons objectForKey: @"R"];
}

- (OHGameControllerButton *)leftTriggerButton
{
	return [_buttons objectForKey: @"ZL"];
}

- (OHGameControllerButton *)rightTriggerButton
{
	return [_buttons objectForKey: @"ZR"];
}

- (OHGameControllerButton *)leftThumbstickButton
{
	return [_buttons objectForKey: @"Left Thumbstick"];
}

- (OHGameControllerButton *)rightThumbstickButton
{
	return [_buttons objectForKey: @"Right Thumbstick"];
}

- (OHGameControllerButton *)menuButton
{
	return [_buttons objectForKey: @"+"];
}

- (OHGameControllerButton *)optionsButton
{
	return [_buttons objectForKey: @"-"];
}

- (OHGameControllerButton *)homeButton
{
	return nil;
}

- (OHGameControllerDirectionalPad *)leftThumbstick
{
	return [_directionalPads objectForKey: @"Left Thumbstick"];
}

- (OHGameControllerDirectionalPad *)rightThumbstick
{
	return [_directionalPads objectForKey: @"Right Thumbstick"];
}

- (OHGameControllerDirectionalPad *)dPad
{
	return [_directionalPads objectForKey: @"D-Pad"];
}
@end

Added src/hid/OHNintendoSwitchGameController.h version [776eb7110c].















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3.0 only,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * version 3.0 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3.0 along with this program. If not, see
 * <https://www.gnu.org/licenses/>.
 */

#import "OHGameController.h"

#define id nx_id
#include <switch.h>
#undef id

OF_ASSUME_NONNULL_BEGIN

@class OHNintendoSwitchExtendedGamepad;

@interface OHNintendoSwitchGameController: OHGameController
{
	PadState _padState;
	OHNintendoSwitchExtendedGamepad *_extendedGamepad;
}

- (instancetype)initWithIndex: (size_t)index;
@end

OF_ASSUME_NONNULL_END

Added src/hid/OHNintendoSwitchGameController.m version [2ac5ac1c04].



























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 3.0 only,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * version 3.0 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3.0 along with this program. If not, see
 * <https://www.gnu.org/licenses/>.
 */

#include "config.h"

#import "OHNintendoSwitchGameController.h"
#import "OFArray.h"
#import "OFDictionary.h"
#import "OHGameControllerAxis.h"
#import "OHGameControllerButton.h"
#import "OHGameControllerDirectionalPad.h"
#import "OHNintendoSwitchExtendedGamepad.h"

#import "OFInitializationFailedException.h"
#import "OFReadFailedException.h"

#define id nx_id
#include <switch.h>
#undef id

static const size_t maxControllers = 8;

@implementation OHNintendoSwitchGameController
@synthesize extendedGamepad = _extendedGamepad;

+ (void)initialize
{
	if (self == [OHNintendoSwitchGameController class])
		padConfigureInput(maxControllers, HidNpadStyleSet_NpadFullCtrl);
}

+ (OFArray OF_GENERIC(OHGameController *) *)controllers
{
	OFMutableArray *controllers = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();

	for (size_t i = 0; i < maxControllers; i++) {
		OHGameController *controller;

		@try {
			controller = [[[OHNintendoSwitchGameController alloc]
			    initWithIndex: i] autorelease];
		} @catch (OFInitializationFailedException *e) {
			/* Controller does not exist. */
			continue;
		}

		[controllers addObject: controller];
	}

	[controllers makeImmutable];

	objc_autoreleasePoolPop(pool);

	return controllers;
}

- (instancetype)initWithIndex: (size_t)index
{
	self = [super init];

	@try {
		padInitialize(&_padState, HidNpadIdType_No1 + index,
		    (index == 0 ? HidNpadIdType_Handheld : 0));
		padUpdate(&_padState);

		if (!(padGetAttributes(&_padState) &
		    HidNpadAttribute_IsConnected))
			@throw [OFInitializationFailedException
			    exceptionWithClass: self.class];

		_extendedGamepad =
		    [[OHNintendoSwitchExtendedGamepad alloc] init];

		[self retrieveState];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_extendedGamepad release];

	[super dealloc];
}

- (void)retrieveState
{
	void *pool = objc_autoreleasePoolPush();
	OFDictionary OF_GENERIC(OFString *, OHGameControllerButton *)
	    *buttons = _extendedGamepad.buttons;
	OFDictionary OF_GENERIC(OFString *, OHGameControllerDirectionalPad *)
	    *directionalPads = _extendedGamepad.directionalPads;
	u64 keys;
	HidAnalogStickState stick;
	OHGameControllerDirectionalPad *directionalPad;

	padUpdate(&_padState);
	keys = padGetButtons(&_padState);

	[[buttons objectForKey: @"A"] setValue: !!(keys & HidNpadButton_A)];
	[[buttons objectForKey: @"B"] setValue: !!(keys & HidNpadButton_B)];
	[[buttons objectForKey: @"X"] setValue: !!(keys & HidNpadButton_X)];
	[[buttons objectForKey: @"Y"] setValue: !!(keys & HidNpadButton_Y)];
	[[buttons objectForKey: @"L"] setValue: !!(keys & HidNpadButton_L)];
	[[buttons objectForKey: @"R"] setValue: !!(keys & HidNpadButton_R)];
	[[buttons objectForKey: @"ZL"] setValue: !!(keys & HidNpadButton_ZL)];
	[[buttons objectForKey: @"ZR"] setValue: !!(keys & HidNpadButton_ZR)];
	[[buttons objectForKey: @"Left Thumbstick"]
	    setValue: !!(keys & HidNpadButton_StickL)];
	[[buttons objectForKey: @"Right Thumbstick"]
	    setValue: !!(keys & HidNpadButton_StickR)];
	[[buttons objectForKey: @"+"] setValue: !!(keys & HidNpadButton_Plus)];
	[[buttons objectForKey: @"-"] setValue: !!(keys & HidNpadButton_Minus)];

	stick = padGetStickPos(&_padState, 0);
	directionalPad = [directionalPads objectForKey: @"Left Thumbstick"];
	[directionalPad.xAxis setValue:
	    (float)stick.x / (stick.x < 0 ? -INT16_MIN : INT16_MAX)];
	[directionalPad.yAxis setValue:
	    -(float)stick.y / (stick.y < 0 ? -INT16_MIN : INT16_MAX)];

	stick = padGetStickPos(&_padState, 1);
	directionalPad = [directionalPads objectForKey: @"Right Thumbstick"];
	[directionalPad.xAxis setValue:
	    (float)stick.x / (stick.x < 0 ? -INT16_MIN : INT16_MAX)];
	[directionalPad.yAxis setValue:
	    -(float)stick.y / (stick.y < 0 ? -INT16_MIN : INT16_MAX)];

	directionalPad = [directionalPads objectForKey: @"D-Pad"];
	[directionalPad.up setValue: !!(keys & keys & HidNpadButton_Up)];
	[directionalPad.down setValue: !!(keys & keys & HidNpadButton_Down)];
	[directionalPad.left setValue: !!(keys & keys & HidNpadButton_Left)];
	[directionalPad.right setValue: !!(keys & keys & HidNpadButton_Right)];

	objc_autoreleasePoolPop(pool);
}

- (OFString *)name
{
	return @"Nintendo Switch";
}

- (id <OHGameControllerProfile>)rawProfile
{
	return _extendedGamepad;
}

- (id <OHGamepad>)gamepad
{
	return _extendedGamepad;
}
@end

Modified src/test/OTAppDelegate.m from [d24b6ba652] to [cffdd964c4].

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
	    [OFString stringWithUTF8String: (const char *)resourcesPath]];

	CFRelease(resourcesURL);
#elif defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS)
	[OFStdIOStream setUpConsole];
#elif defined(OF_NINTENDO_SWITCH)
	consoleInit(NULL);
	padConfigureInput(1, HidNpadStyleSet_NpadStandard);
	updateConsole(true);
#endif
}

- (OFMutableSet OF_GENERIC(Class) *)testClasses
{
	Class *classes;







<







110
111
112
113
114
115
116

117
118
119
120
121
122
123
	    [OFString stringWithUTF8String: (const char *)resourcesPath]];

	CFRelease(resourcesURL);
#elif defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS)
	[OFStdIOStream setUpConsole];
#elif defined(OF_NINTENDO_SWITCH)
	consoleInit(NULL);

	updateConsole(true);
#endif
}

- (OFMutableSet OF_GENERIC(Class) *)testClasses
{
	Class *classes;
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
		if (description != nil)
			[OFStdOut writeLine: description];

		break;
	}

	if (status == StatusFailed) {
#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS)

		[OFStdOut setForegroundColor: [OFColor silver]];
		[OFStdOut writeLine: @"Press A to continue"];




		for (;;) {

			void *pool = objc_autoreleasePoolPush();
			OHGameController *controller =
			    [[OHGameController controllers] objectAtIndex: 0];
			OHGameControllerButton *button =
			    [controller.rawProfile.buttons objectForKey: @"A"];

			[controller retrieveState];

			if (button.pressed)
				break;




			[OFThread waitForVerticalBlank];


			objc_autoreleasePoolPop(pool);
		}
#elif defined(OF_NINTENDO_SWITCH)
		[OFStdOut setForegroundColor: [OFColor silver]];
		[OFStdOut writeLine: @"Press A to continue"];

		while (appletMainLoop()) {
			PadState pad;

			padUpdate(&pad);
			updateConsole(true);

			if (padGetButtonsDown(&pad) & HidNpadButton_A)
				break;
		}
#endif
	}
}

- (OFString *)descriptionForException: (id)exception
{
	OFMutableString *description = [OFMutableString







|
>



>
>
>

>











>
>
>

>



<
<
<
<
<
<
<
<
<
<
<
<
<







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
		if (description != nil)
			[OFStdOut writeLine: description];

		break;
	}

	if (status == StatusFailed) {
#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS) || \
    defined(OF_NINTENDO_SWITCH)
		[OFStdOut setForegroundColor: [OFColor silver]];
		[OFStdOut writeLine: @"Press A to continue"];

# ifdef OF_NINTENDO_SWITCH
		while (appletMainLoop()) {
# else
		for (;;) {
# endif
			void *pool = objc_autoreleasePoolPush();
			OHGameController *controller =
			    [[OHGameController controllers] objectAtIndex: 0];
			OHGameControllerButton *button =
			    [controller.rawProfile.buttons objectForKey: @"A"];

			[controller retrieveState];

			if (button.pressed)
				break;

# ifdef OF_NINTENDO_SWITCH
			updateConsole(true);
# else
			[OFThread waitForVerticalBlank];
# endif

			objc_autoreleasePoolPop(pool);
		}













#endif
	}
}

- (OFString *)descriptionForException: (id)exception
{
	OFMutableString *description = [OFMutableString

Modified tests/gamecontroller/GameControllerTests.m from [e80833a68c] to [aae21c76af].

43
44
45
46
47
48
49
50

51
52
53
54






55
56
57
58
59
60
61
static size_t buttonsPerLine = 2;
#elif defined(OF_NINTENDO_3DS)
static size_t buttonsPerLine = 3;
#else
static size_t buttonsPerLine = 5;
#endif

#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS)

# define red maroon
# define yellow olive
# define gray silver
#endif







@interface GameControllerTests: OFObject <OFApplicationDelegate>
{
	OFArray OF_GENERIC(OHGameController *) *_controllers;
	OFDate *_lastControllersUpdate;
}
@end







|
>




>
>
>
>
>
>







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
static size_t buttonsPerLine = 2;
#elif defined(OF_NINTENDO_3DS)
static size_t buttonsPerLine = 3;
#else
static size_t buttonsPerLine = 5;
#endif

#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS) || \
    defined(OF_NINTENDO_SWITCH)
# define red maroon
# define yellow olive
# define gray silver
#endif

#ifdef OF_NINTENDO_SWITCH
# define id nx_id
# include <switch.h>
# undef id
#endif

@interface GameControllerTests: OFObject <OFApplicationDelegate>
{
	OFArray OF_GENERIC(OHGameController *) *_controllers;
	OFDate *_lastControllersUpdate;
}
@end
176
177
178
179
180
181
182



183



184

185
186
187
188
189
190
191

@implementation GameControllerTests
- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS)
	[OFStdIOStream setUpConsole];
#endif







	for (;;) {

		void *pool = objc_autoreleasePoolPush();
		OHGameController *leftJoyCon = nil, *rightJoyCon = nil;

		if (_lastControllersUpdate == nil ||
		    -[_lastControllersUpdate timeIntervalSinceNow] > 1) {
			[_controllers release];
			[_lastControllersUpdate release];







>
>
>

>
>
>

>







183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

@implementation GameControllerTests
- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS)
	[OFStdIOStream setUpConsole];
#endif
#if defined(OF_NINTENDO_SWITCH)
	consoleInit(NULL);
#endif

#ifdef OF_NINTENDO_SWITCH
	while (appletMainLoop()) {
#else
	for (;;) {
#endif
		void *pool = objc_autoreleasePoolPush();
		OHGameController *leftJoyCon = nil, *rightJoyCon = nil;

		if (_lastControllersUpdate == nil ||
		    -[_lastControllersUpdate timeIntervalSinceNow] > 1) {
			[_controllers release];
			[_lastControllersUpdate release];
240
241
242
243
244
245
246


247
248
249
250
251
252
253
254
			[OFStdOut writeLine: @"Combined Joy-Cons"];

			printProfile(combinedJoyCons);
		}

#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS)
		[OFThread waitForVerticalBlank];


#else
		[OFThread sleepForTimeInterval: 1.f / 60.f];
#endif

		objc_autoreleasePoolPop(pool);
	}
}
@end







>
>








254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
			[OFStdOut writeLine: @"Combined Joy-Cons"];

			printProfile(combinedJoyCons);
		}

#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS)
		[OFThread waitForVerticalBlank];
#elif defined(OF_NINTENDO_SWITCH)
		consoleUpdate(NULL);
#else
		[OFThread sleepForTimeInterval: 1.f / 60.f];
#endif

		objc_autoreleasePoolPop(pool);
	}
}
@end

Modified tests/gamecontroller/Makefile from [5719799b8f] to [3a888c2fc9].

1
2
3
4
5
6

7
8
9
10
11
12
13
include ../../extra.mk

CLEAN = boot.dol		\
	${PROG_NOINST}.3dsx	\
	${PROG_NOINST}.arm9	\
	${PROG_NOINST}.ndsd	\


PROG_NOINST = tests${PROG_SUFFIX}
SRCS = GameControllerTests.m

include ../../buildsys.mk

.PHONY: run





|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
include ../../extra.mk

CLEAN = boot.dol		\
	${PROG_NOINST}.3dsx	\
	${PROG_NOINST}.arm9	\
	${PROG_NOINST}.nds	\
	${PROG_NOINST}.nro

PROG_NOINST = tests${PROG_SUFFIX}
SRCS = GameControllerTests.m

include ../../buildsys.mk

.PHONY: run
105
106
107
108
109
110
111



112
113
114
115
116
117
118
119
120
121
122
123
	3dsxtool $< $@

${PROG_NOINST}.arm9: ${PROG_NOINST}
	arm-none-eabi-objcopy -O binary $< $@

${PROG_NOINST}.nds: ${PROG_NOINST}.arm9
	ndstool -c $@ -9 ${PROG_NOINST}




CPPFLAGS += -I../../src			\
	    -I../../src/exceptions	\
	    -I../../src/hid		\
	    -I../../src/runtime		\
	    -I../..			\
	    -DOBJFWHID_LOCAL_INCLUDES
LIBS := -L../../src/hid -lobjfwhid ${HID_LIBS}	\
	-L../../src -lobjfw			\
	-L../../src/runtime ${RUNTIME_LIBS}	\
	${LIBS}
LD = ${OBJC}







>
>
>












106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
	3dsxtool $< $@

${PROG_NOINST}.arm9: ${PROG_NOINST}
	arm-none-eabi-objcopy -O binary $< $@

${PROG_NOINST}.nds: ${PROG_NOINST}.arm9
	ndstool -c $@ -9 ${PROG_NOINST}

${PROG_NOINST}.nro: ${PROG_NOINST}
	elf2nro ${PROG_NOINST} $@

CPPFLAGS += -I../../src			\
	    -I../../src/exceptions	\
	    -I../../src/hid		\
	    -I../../src/runtime		\
	    -I../..			\
	    -DOBJFWHID_LOCAL_INCLUDES
LIBS := -L../../src/hid -lobjfwhid ${HID_LIBS}	\
	-L../../src -lobjfw			\
	-L../../src/runtime ${RUNTIME_LIBS}	\
	${LIBS}
LD = ${OBJC}