commit 20fcde0
zzo38
·
2023-04-15 00:33:12 +0000 UTC
parent 369f750
Implement joystick mode (currently untested; I do not have a joystick on my computer; someone who does have can test it)
2 files changed,
+169,
-2
M
main.c
+38,
-0
1@@ -10,6 +10,9 @@
2 -I
3 Use a separate thread to read from stdin.
4
5+-J #
6+ Set joystick mode. See the below section about joystick for details.
7+
8 -N
9 Tells the window manager to omit the frame.
10
11@@ -154,6 +157,41 @@ are being used, then this number may be set higher than 273.
12 (Currently there is not the setting of interpolation, filter, etc.)
13
14
15+=== Joystick ===
16+
17+The joystick parameter can be ? to list joysticks, or ? and a number to
18+display details about that joystick, or it can be the below specification
19+in order to configure joysticks.
20+
21+The first part is numbers with commas in between, being the joystick ID
22+numbers (as shown by the ? list); up to four numbers can be specified. If
23+a number is omitted, then that slot is not used.
24+
25+After the first part is a forward slash, and then the mapping (all
26+joysticks must use an identical mapping). Each item is a letter and then
27+a number, with no delimiters in between. The letters can be:
28+
29+A B S T U D L R
30+ Specify which joystick button to map to the uxn joypad button;
31+ respectively, A, B, SELECT, START, UP, DOWN, LEFT, RIGHT. Only the first
32+ 128 buttons can be mapped.
33+
34+X Y x y
35+ Specify which axis to use as the X and Y axis. Uppercase letters means
36+ that axis is reversed; do not specify both "X" and "x", and do not
37+ specify both "Y" and "y".
38+
39+s
40+ Set sensitivity, from 1 to 32767. Higher numbers mean the joystick must
41+ be moved more in order to register, while lower numbers means that it
42+ does not need to moved much in order to be registered.
43+
44+H h I i
45+ Specify the hat number to use. Different letters correspond to different
46+ orientations (specify only up to one of these letters, not all of them).
47+ "h" is normal, "H" is reverse, "I" and "i" are sideways.
48+
49+
50 === Nonstandard features ===
51
52 The -x switch enables the following nonstandard features, which include
M
main.c
+131,
-2
1@@ -226,6 +226,13 @@ static SDL_Thread*in_thread;
2 static Sint32*audio_option;
3 static SDL_AudioSpec audiospec;
4
5+static Uint8 joy_mask;
6+static Uint8 joy_player[4];
7+static Uint8 joy_hat,joy_hat_mode;
8+static Uint8 joy_axis_x,joy_axis_y,joy_axis_mode;
9+static Uint8 joy_button_map[128];
10+static Uint16 joy_sensitivity=8192;
11+
12 static Uint8 debugger=0;
13 static Uint16 breakpoint=0;
14 static Uint16 break_pc=0x0100;
15@@ -1140,6 +1147,14 @@ static void redraw(void) {
16 SDL_Flip(screen);
17 }
18
19+static inline int select_joystick(Uint8 n) {
20+ if((joy_mask&1) && n==joy_player[0]) return 2;
21+ if((joy_mask&2) && n==joy_player[1]) return 5;
22+ if((joy_mask&4) && n==joy_player[2]) return 6;
23+ if((joy_mask&8) && n==joy_player[3]) return 7;
24+ return 0;
25+}
26+
27 static int run_screen(void) {
28 SDL_Event e;
29 int i,j,k;
30@@ -1236,6 +1251,49 @@ static int run_screen(void) {
31 device[1].d[2]=e.user.code;
32 run(GET16(device[1].d));
33 break;
34+ case SDL_JOYAXISMOTION:
35+ if(!joy_axis_mode) break;
36+ if(j=select_joystick(e.jaxis.which)) {
37+ k=device[8].d[j];
38+ if(e.jaxis.axis==joy_axis_x) {
39+ i=e.jaxis.value*(joy_axis_mode&1?-1:1);
40+ k&=0x3F;
41+ if(i>=joy_sensitivity) k|=0x80; else if(i<=-joy_sensitivity) k|=0x40;
42+ } else if(e.jaxis.axis==joy_axis_y) {
43+ i=e.jaxis.value*(joy_axis_mode&2?-1:1);
44+ k&=0xCF;
45+ if(i>=joy_sensitivity) k|=0x10; else if(i<=-joy_sensitivity) k|=0x20;
46+ }
47+ trigger:
48+ if(k!=device[8].d[j]) {
49+ device[8].d[j]=k;
50+ if(!paused) run(GET16(device[8].d));
51+ }
52+ }
53+ break;
54+ case SDL_JOYBUTTONDOWN:
55+ case SDL_JOYBUTTONUP:
56+ if(e.jbutton.button&~127) break;
57+ if(j=select_joystick(e.jbutton.which)) {
58+ k=device[8].d[j];
59+ i=joy_button_map[e.jbutton.button];
60+ if(e.jbutton.state==SDL_PRESSED) k|=i; else k&=~i;
61+ goto trigger;
62+ }
63+ break;
64+ case SDL_JOYHATMOTION:
65+ if(!joy_hat_mode) break;
66+ if(j=select_joystick(e.jhat.which)) {
67+ k=device[8].d[j]&0x0F;
68+ // Note that the SDL_HAT_ values are bits counted clockwise from UP.
69+ i=(e.jhat.value*0x1111)>>joy_hat_mode;
70+ if(i&SDL_HAT_UP) k|=0x10;
71+ if(i&SDL_HAT_DOWN) k|=0x20;
72+ if(i&SDL_HAT_LEFT) k|=0x40;
73+ if(i&SDL_HAT_RIGHT) k|=0x80;
74+ goto trigger;
75+ }
76+ break;
77 }
78 if(picture_changed) redraw();
79 }
80@@ -1290,6 +1348,69 @@ static void set_audio(char*s) {
81 if(!audio_option['e'-'a']) audio_option['e'-'a']=audio_option['r'-'a']/15;
82 }
83
84+static void set_joystick(char*s) {
85+ int c,i,n;
86+ SDL_Joystick*j;
87+ if(*s=='?') {
88+ if(SDL_Init(SDL_INIT_JOYSTICK|SDL_INIT_NOPARACHUTE)) errx(1,"Cannot initialize SDL: %s",SDL_GetError());
89+ atexit(SDL_Quit);
90+ if(s[1]) {
91+ j=SDL_JoystickOpen(i=strtol(s+1,0,10));
92+ if(!j) errx(1,"Cannot open joystick %d",i);
93+ printf("Opened Joystick %d\n",i);
94+ printf("Name: %s\n",SDL_JoystickName(i));
95+ printf("Axes: %d\n",SDL_JoystickNumAxes(j));
96+ printf("Buttons: %d\n",SDL_JoystickNumButtons(j));
97+ printf("Hats: %d\n",SDL_JoystickNumHats(j));
98+ printf("Balls: %d\n",SDL_JoystickNumBalls(j));
99+ SDL_JoystickClose(j);
100+ } else {
101+ n=SDL_NumJoysticks();
102+ for(i=0;i<n;i++) printf("%d: %s\n",i,SDL_JoystickName(i));
103+ }
104+ exit(0);
105+ return;
106+ }
107+ n=0;
108+ while(*s) {
109+ if(*s>='0' && *s<='9') {
110+ if(n&~3) errx(1,"Too many players");
111+ joy_player[n]=strtol(s,&s,10);
112+ joy_mask|=1<<n;
113+ } else if(*s==',') {
114+ s++;
115+ n++;
116+ } else {
117+ break;
118+ }
119+ }
120+ if(*s=='/') ++s; else errx(1,"Improper joystick setting");
121+ while(*s) {
122+ c=*s++;
123+ n=strtol(s,&s,10);
124+ switch(c) {
125+ case 'A': joy_button_map[n&0x7F]|=0x01; break;
126+ case 'B': joy_button_map[n&0x7F]|=0x02; break;
127+ case 'D': joy_button_map[n&0x7F]|=0x20; break;
128+ case 'H': joy_hat=n; joy_hat_mode=6; break;
129+ case 'h': joy_hat=n; joy_hat_mode=4; break;
130+ case 'I': joy_hat=n; joy_hat_mode=5; break;
131+ case 'i': joy_hat=n; joy_hat_mode=7; break;
132+ case 'L': joy_button_map[n&0x7F]|=0x40; break;
133+ case 'R': joy_button_map[n&0x7F]|=0x80; break;
134+ case 'S': joy_button_map[n&0x7F]|=0x04; break;
135+ case 'T': joy_button_map[n&0x7F]|=0x08; break;
136+ case 'U': joy_button_map[n&0x7F]|=0x10; break;
137+ case 'X': joy_axis_x=n; joy_axis_mode|=1; break;
138+ case 'Y': joy_axis_y=n; joy_axis_mode|=2; break;
139+ case 's': joy_sensitivity=n; break;
140+ case 'x': joy_axis_x=n; joy_axis_mode|=4; break;
141+ case 'y': joy_axis_y=n; joy_axis_mode|=8; break;
142+ default: errx(1,"Improper joystick setting");
143+ }
144+ }
145+}
146+
147 int main(int argc,char**argv) {
148 int i,j;
149 for(i=0;i<16;i++) {
150@@ -1300,10 +1421,11 @@ int main(int argc,char**argv) {
151 device[10].aux=&uxnfile0;
152 device[11].aux=&uxnfile1;
153 device[12].in=datetime_in;
154- while((i=getopt(argc,argv,"+ADFINQST:YZa:dh:ijnp:qs:t:w:xyz:"))>0) switch(i) {
155+ while((i=getopt(argc,argv,"+ADFIJ:NQST:YZa:dh:ijnp:qs:t:w:xyz:"))>0) switch(i) {
156 case 'D': scrflags|=SDL_DOUBLEBUF; break;
157 case 'F': scrflags|=SDL_FULLSCREEN; break;
158 case 'I': use_thread=1; break;
159+ case 'J': set_joystick(optarg); break;
160 case 'N': scrflags|=SDL_NOFRAME; break;
161 case 'Q': use_mouse=0; break;
162 case 'S': disallow_size_change=1; break;
163@@ -1332,7 +1454,7 @@ int main(int argc,char**argv) {
164 if(use_screen) {
165 if(zoom<1) errx(1,"Zoom out of range");
166 if(default_height<1 || default_width<1) errx(1,"Screen size out of range");
167- if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|(audio_option?SDL_INIT_AUDIO:0))) errx(1,"Cannot initialize SDL: %s",SDL_GetError());
168+ if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|(audio_option?SDL_INIT_AUDIO:0)|(joy_mask?SDL_INIT_JOYSTICK:0))) errx(1,"Cannot initialize SDL: %s",SDL_GetError());
169 atexit(SDL_Quit);
170 device[2].out=screen_out;
171 scr_w=default_width;
172@@ -1340,6 +1462,13 @@ int main(int argc,char**argv) {
173 PUT16(device[2].d+2,scr_w);
174 PUT16(device[2].d+4,scr_h);
175 size_changed=1;
176+ if(joy_mask) {
177+ if((joy_mask&1) && !SDL_JoystickOpen(joy_player[0])) errx(1,"Cannot open joystick for player I");
178+ if((joy_mask&2) && !SDL_JoystickOpen(joy_player[1])) errx(1,"Cannot open joystick for player II");
179+ if((joy_mask&4) && !SDL_JoystickOpen(joy_player[2])) errx(1,"Cannot open joystick for player III");
180+ if((joy_mask&8) && !SDL_JoystickOpen(joy_player[3])) errx(1,"Cannot open joystick for player IV");
181+ SDL_JoystickEventState(SDL_ENABLE);
182+ }
183 }
184 if(use_console) device[1].out=console_out;
185 if(device[12].d[15]) device[12].d[15]=0; else device[12].in=datetime_in;