Mercurial > sdl-ios-xcode
annotate src/cdrom/freebsd/SDL_syscdrom.c @ 4170:092c0bc69155 SDL-1.2
Fixed bug #618
Description From Tim Angus 2008-08-30 12:23:56 (-) [reply]
As we all know SDL 1.2 doesn't handle dead keys well since one key press
potentially equals two (or more) characters. For example, on many layouts,
keying <backquote>,<space> results in <no character>,<backquote><space>. Since
the unicode member of the SDL_keysym struct only has room for one character,
only one can be returned.
On Linux, the first character is returned. On Windows however, unless the exact
number of characters generated by the keypress is 1, nothing is returned. The
following patch addresses this inconsistency.
Updated patch which includes a further fix to the handling of the numpad when
numlock is on. This further fix is courtesy Amanieu d'Antras.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 13 Apr 2009 08:42:09 +0000 |
parents | a1b03ba2fcd0 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
4159 | 3 Copyright (C) 1997-2009 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
6 modify it under the terms of the GNU Lesser General Public |
0 | 7 License as published by the Free Software Foundation; either |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
8 version 2.1 of the License, or (at your option) any later version. |
0 | 9 |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
13 Lesser General Public License for more details. |
0 | 14 |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
15 You should have received a copy of the GNU Lesser General Public |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
16 License along with this library; if not, write to the Free Software |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
1402
d910939febfa
Use consistent identifiers for the various platforms we support.
Sam Lantinga <slouken@libsdl.org>
parents:
1379
diff
changeset
|
22 #include "SDL_config.h" |
0 | 23 |
1635
92947e3a18db
Make sure code is only compiled if the appropriate subsystem is enabled
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
24 #ifdef SDL_CDROM_FREEBSD |
92947e3a18db
Make sure code is only compiled if the appropriate subsystem is enabled
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
25 |
0 | 26 /* Functions for system-level CD-ROM audio control */ |
27 | |
28 #include <sys/types.h> | |
29 #include <sys/stat.h> | |
30 #include <fcntl.h> | |
31 #include <errno.h> | |
32 #include <unistd.h> | |
33 #include <sys/cdio.h> | |
34 | |
35 #include "SDL_cdrom.h" | |
1361
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
36 #include "../SDL_syscdrom.h" |
0 | 37 |
38 | |
39 /* The maximum number of CD-ROM drives we'll detect */ | |
40 #define MAX_DRIVES 16 | |
41 | |
42 /* A list of available CD-ROM drives */ | |
43 static char *SDL_cdlist[MAX_DRIVES]; | |
44 static dev_t SDL_cdmode[MAX_DRIVES]; | |
45 | |
46 /* The system-dependent CD control functions */ | |
47 static const char *SDL_SYS_CDName(int drive); | |
48 static int SDL_SYS_CDOpen(int drive); | |
49 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom); | |
50 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position); | |
51 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length); | |
52 static int SDL_SYS_CDPause(SDL_CD *cdrom); | |
53 static int SDL_SYS_CDResume(SDL_CD *cdrom); | |
54 static int SDL_SYS_CDStop(SDL_CD *cdrom); | |
55 static int SDL_SYS_CDEject(SDL_CD *cdrom); | |
56 static void SDL_SYS_CDClose(SDL_CD *cdrom); | |
57 | |
58 /* Some ioctl() errno values which occur when the tray is empty */ | |
59 #define ERRNO_TRAYEMPTY(errno) \ | |
60 ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL)) | |
61 | |
62 /* Check a drive to see if it is a CD-ROM */ | |
63 static int CheckDrive(char *drive, struct stat *stbuf) | |
64 { | |
65 int is_cd, cdfd; | |
66 struct ioc_read_subchannel info; | |
67 | |
68 /* If it doesn't exist, return -1 */ | |
69 if ( stat(drive, stbuf) < 0 ) { | |
70 return(-1); | |
71 } | |
72 | |
73 /* If it does exist, verify that it's an available CD-ROM */ | |
74 is_cd = 0; | |
75 if ( S_ISCHR(stbuf->st_mode) || S_ISBLK(stbuf->st_mode) ) { | |
76 cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); | |
77 if ( cdfd >= 0 ) { | |
78 info.address_format = CD_MSF_FORMAT; | |
79 info.data_format = CD_CURRENT_POSITION; | |
80 info.data_len = 0; | |
81 info.data = NULL; | |
82 /* Under Linux, EIO occurs when a disk is not present. | |
83 This isn't 100% reliable, so we use the USE_MNTENT | |
84 code above instead. | |
85 */ | |
86 if ( (ioctl(cdfd, CDIOCREADSUBCHANNEL, &info) == 0) || | |
87 ERRNO_TRAYEMPTY(errno) ) { | |
88 is_cd = 1; | |
89 } | |
90 close(cdfd); | |
91 } | |
92 } | |
93 return(is_cd); | |
94 } | |
95 | |
96 /* Add a CD-ROM drive to our list of valid drives */ | |
97 static void AddDrive(char *drive, struct stat *stbuf) | |
98 { | |
99 int i; | |
100 | |
101 if ( SDL_numcds < MAX_DRIVES ) { | |
102 /* Check to make sure it's not already in our list. | |
103 This can happen when we see a drive via symbolic link. | |
104 */ | |
105 for ( i=0; i<SDL_numcds; ++i ) { | |
106 if ( stbuf->st_rdev == SDL_cdmode[i] ) { | |
107 #ifdef DEBUG_CDROM | |
108 fprintf(stderr, "Duplicate drive detected: %s == %s\n", drive, SDL_cdlist[i]); | |
109 #endif | |
110 return; | |
111 } | |
112 } | |
113 | |
114 /* Add this drive to our list */ | |
115 i = SDL_numcds; | |
1379
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
116 SDL_cdlist[i] = SDL_strdup(drive); |
0 | 117 if ( SDL_cdlist[i] == NULL ) { |
118 SDL_OutOfMemory(); | |
119 return; | |
120 } | |
121 SDL_cdmode[i] = stbuf->st_rdev; | |
122 ++SDL_numcds; | |
123 #ifdef DEBUG_CDROM | |
124 fprintf(stderr, "Added CD-ROM drive: %s\n", drive); | |
125 #endif | |
126 } | |
127 } | |
128 | |
129 int SDL_SYS_CDInit(void) | |
130 { | |
131 /* checklist: /dev/cdrom,/dev/cd?c /dev/acd?c | |
132 /dev/matcd?c /dev/mcd?c /dev/scd?c */ | |
133 static char *checklist[] = { | |
134 "cdrom", "?0 cd?", "?0 acd?", "?0 matcd?", "?0 mcd?", "?0 scd?",NULL | |
135 }; | |
136 char *SDLcdrom; | |
137 int i, j, exists; | |
138 char drive[32]; | |
139 struct stat stbuf; | |
140 | |
141 /* Fill in our driver capabilities */ | |
142 SDL_CDcaps.Name = SDL_SYS_CDName; | |
143 SDL_CDcaps.Open = SDL_SYS_CDOpen; | |
144 SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC; | |
145 SDL_CDcaps.Status = SDL_SYS_CDStatus; | |
146 SDL_CDcaps.Play = SDL_SYS_CDPlay; | |
147 SDL_CDcaps.Pause = SDL_SYS_CDPause; | |
148 SDL_CDcaps.Resume = SDL_SYS_CDResume; | |
149 SDL_CDcaps.Stop = SDL_SYS_CDStop; | |
150 SDL_CDcaps.Eject = SDL_SYS_CDEject; | |
151 SDL_CDcaps.Close = SDL_SYS_CDClose; | |
152 | |
153 /* Look in the environment for our CD-ROM drive list */ | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
154 SDLcdrom = SDL_getenv("SDL_CDROM"); /* ':' separated list of devices */ |
0 | 155 if ( SDLcdrom != NULL ) { |
156 char *cdpath, *delim; | |
1379
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
157 size_t len = SDL_strlen(SDLcdrom)+1; |
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
158 cdpath = SDL_stack_alloc(char, len); |
0 | 159 if ( cdpath != NULL ) { |
1379
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
160 SDL_strlcpy(cdpath, SDLcdrom, len); |
0 | 161 SDLcdrom = cdpath; |
162 do { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
163 delim = SDL_strchr(SDLcdrom, ':'); |
0 | 164 if ( delim ) { |
165 *delim++ = '\0'; | |
166 } | |
167 if ( CheckDrive(SDLcdrom, &stbuf) > 0 ) { | |
168 AddDrive(SDLcdrom, &stbuf); | |
169 } | |
170 if ( delim ) { | |
171 SDLcdrom = delim; | |
172 } else { | |
173 SDLcdrom = NULL; | |
174 } | |
175 } while ( SDLcdrom ); | |
1379
c0a74f199ecf
Use only safe string functions
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
176 SDL_stack_free(cdpath); |
0 | 177 } |
178 | |
179 /* If we found our drives, there's nothing left to do */ | |
180 if ( SDL_numcds > 0 ) { | |
181 return(0); | |
182 } | |
183 } | |
184 | |
185 /* Scan the system for CD-ROM drives */ | |
186 for ( i=0; checklist[i]; ++i ) { | |
187 if ( checklist[i][0] == '?' ) { | |
188 char *insert; | |
189 exists = 1; | |
190 for ( j=checklist[i][1]; exists; ++j ) { | |
1338
604d73db6802
Removed uses of stdlib.h and string.h
Sam Lantinga <slouken@libsdl.org>
parents:
1336
diff
changeset
|
191 SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%sc", &checklist[i][3]); |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
192 insert = SDL_strchr(drive, '?'); |
0 | 193 if ( insert != NULL ) { |
194 *insert = j; | |
195 } | |
196 switch (CheckDrive(drive, &stbuf)) { | |
197 /* Drive exists and is a CD-ROM */ | |
198 case 1: | |
199 AddDrive(drive, &stbuf); | |
200 break; | |
201 /* Drive exists, but isn't a CD-ROM */ | |
202 case 0: | |
203 break; | |
204 /* Drive doesn't exist */ | |
205 case -1: | |
206 exists = 0; | |
207 break; | |
208 } | |
209 } | |
210 } else { | |
1338
604d73db6802
Removed uses of stdlib.h and string.h
Sam Lantinga <slouken@libsdl.org>
parents:
1336
diff
changeset
|
211 SDL_snprintf(drive, SDL_arraysize(drive), "/dev/%s", checklist[i]); |
0 | 212 if ( CheckDrive(drive, &stbuf) > 0 ) { |
213 AddDrive(drive, &stbuf); | |
214 } | |
215 } | |
216 } | |
217 return(0); | |
218 } | |
219 | |
220 /* General ioctl() CD-ROM command function */ | |
221 static int SDL_SYS_CDioctl(int id, int command, void *arg) | |
222 { | |
223 int retval; | |
224 | |
225 retval = ioctl(id, command, arg); | |
226 if ( retval < 0 ) { | |
227 SDL_SetError("ioctl() error: %s", strerror(errno)); | |
228 } | |
229 return(retval); | |
230 } | |
231 | |
232 static const char *SDL_SYS_CDName(int drive) | |
233 { | |
234 return(SDL_cdlist[drive]); | |
235 } | |
236 | |
237 static int SDL_SYS_CDOpen(int drive) | |
238 { | |
239 return(open(SDL_cdlist[drive], (O_RDONLY|O_EXCL|O_NONBLOCK), 0)); | |
240 } | |
241 | |
242 static int SDL_SYS_CDGetTOC(SDL_CD *cdrom) | |
243 { | |
244 struct ioc_toc_header toc; | |
245 int i, okay; | |
246 struct ioc_read_toc_entry entry; | |
247 struct cd_toc_entry data; | |
248 | |
249 okay = 0; | |
250 if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCHEADER, &toc) == 0 ) { | |
251 cdrom->numtracks = toc.ending_track-toc.starting_track+1; | |
252 if ( cdrom->numtracks > SDL_MAX_TRACKS ) { | |
253 cdrom->numtracks = SDL_MAX_TRACKS; | |
254 } | |
255 /* Read all the track TOC entries */ | |
256 for ( i=0; i<=cdrom->numtracks; ++i ) { | |
257 if ( i == cdrom->numtracks ) { | |
258 cdrom->track[i].id = 0xAA; /* CDROM_LEADOUT */ | |
259 } else { | |
260 cdrom->track[i].id = toc.starting_track+i; | |
261 } | |
262 entry.starting_track = cdrom->track[i].id; | |
263 entry.address_format = CD_MSF_FORMAT; | |
264 entry.data_len = sizeof(data); | |
265 entry.data = &data; | |
266 if ( SDL_SYS_CDioctl(cdrom->id, CDIOREADTOCENTRYS, | |
267 &entry) < 0 ) { | |
268 break; | |
269 } else { | |
270 cdrom->track[i].type = data.control; | |
271 cdrom->track[i].offset = MSF_TO_FRAMES( | |
272 data.addr.msf.minute, | |
273 data.addr.msf.second, | |
274 data.addr.msf.frame); | |
275 cdrom->track[i].length = 0; | |
276 if ( i > 0 ) { | |
277 cdrom->track[i-1].length = | |
278 cdrom->track[i].offset- | |
279 cdrom->track[i-1].offset; | |
280 } | |
281 } | |
282 } | |
283 if ( i == (cdrom->numtracks+1) ) { | |
284 okay = 1; | |
285 } | |
286 } | |
287 return(okay ? 0 : -1); | |
288 } | |
289 | |
290 /* Get CD-ROM status */ | |
291 static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position) | |
292 { | |
293 CDstatus status; | |
294 struct ioc_toc_header toc; | |
295 struct ioc_read_subchannel info; | |
296 struct cd_sub_channel_info data; | |
297 | |
298 info.address_format = CD_MSF_FORMAT; | |
299 info.data_format = CD_CURRENT_POSITION; | |
300 info.track = 0; | |
301 info.data_len = sizeof(data); | |
302 info.data = &data; | |
303 if ( ioctl(cdrom->id, CDIOCREADSUBCHANNEL, &info) < 0 ) { | |
304 if ( ERRNO_TRAYEMPTY(errno) ) { | |
305 status = CD_TRAYEMPTY; | |
306 } else { | |
307 status = CD_ERROR; | |
308 } | |
309 } else { | |
310 switch (data.header.audio_status) { | |
311 case CD_AS_AUDIO_INVALID: | |
312 case CD_AS_NO_STATUS: | |
313 /* Try to determine if there's a CD available */ | |
314 if (ioctl(cdrom->id,CDIOREADTOCHEADER,&toc)==0) | |
315 status = CD_STOPPED; | |
316 else | |
317 status = CD_TRAYEMPTY; | |
318 break; | |
319 case CD_AS_PLAY_COMPLETED: | |
320 status = CD_STOPPED; | |
321 break; | |
322 case CD_AS_PLAY_IN_PROGRESS: | |
323 status = CD_PLAYING; | |
324 break; | |
325 case CD_AS_PLAY_PAUSED: | |
326 status = CD_PAUSED; | |
327 break; | |
328 default: | |
329 status = CD_ERROR; | |
330 break; | |
331 } | |
332 } | |
333 if ( position ) { | |
334 if ( status == CD_PLAYING || (status == CD_PAUSED) ) { | |
335 *position = MSF_TO_FRAMES( | |
336 data.what.position.absaddr.msf.minute, | |
337 data.what.position.absaddr.msf.second, | |
338 data.what.position.absaddr.msf.frame); | |
339 } else { | |
340 *position = 0; | |
341 } | |
342 } | |
343 return(status); | |
344 } | |
345 | |
346 /* Start play */ | |
347 static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length) | |
348 { | |
349 struct ioc_play_msf playtime; | |
350 | |
351 FRAMES_TO_MSF(start, | |
352 &playtime.start_m, &playtime.start_s, &playtime.start_f); | |
353 FRAMES_TO_MSF(start+length, | |
354 &playtime.end_m, &playtime.end_s, &playtime.end_f); | |
355 #ifdef DEBUG_CDROM | |
356 fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n", | |
357 playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0, | |
358 playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1); | |
359 #endif | |
360 ioctl(cdrom->id, CDIOCSTART, 0); | |
361 return(SDL_SYS_CDioctl(cdrom->id, CDIOCPLAYMSF, &playtime)); | |
362 } | |
363 | |
364 /* Pause play */ | |
365 static int SDL_SYS_CDPause(SDL_CD *cdrom) | |
366 { | |
367 return(SDL_SYS_CDioctl(cdrom->id, CDIOCPAUSE, 0)); | |
368 } | |
369 | |
370 /* Resume play */ | |
371 static int SDL_SYS_CDResume(SDL_CD *cdrom) | |
372 { | |
373 return(SDL_SYS_CDioctl(cdrom->id, CDIOCRESUME, 0)); | |
374 } | |
375 | |
376 /* Stop play */ | |
377 static int SDL_SYS_CDStop(SDL_CD *cdrom) | |
378 { | |
379 return(SDL_SYS_CDioctl(cdrom->id, CDIOCSTOP, 0)); | |
380 } | |
381 | |
382 /* Eject the CD-ROM */ | |
383 static int SDL_SYS_CDEject(SDL_CD *cdrom) | |
384 { | |
385 return(SDL_SYS_CDioctl(cdrom->id, CDIOCEJECT, 0)); | |
386 } | |
387 | |
388 /* Close the CD-ROM handle */ | |
389 static void SDL_SYS_CDClose(SDL_CD *cdrom) | |
390 { | |
391 close(cdrom->id); | |
392 } | |
393 | |
394 void SDL_SYS_CDQuit(void) | |
395 { | |
396 int i; | |
397 | |
398 if ( SDL_numcds > 0 ) { | |
399 for ( i=0; i<SDL_numcds; ++i ) { | |
1336
3692456e7b0f
Use SDL_ prefixed versions of C library functions.
Sam Lantinga <slouken@libsdl.org>
parents:
1312
diff
changeset
|
400 SDL_free(SDL_cdlist[i]); |
0 | 401 } |
402 SDL_numcds = 0; | |
403 } | |
404 } | |
405 | |
1635
92947e3a18db
Make sure code is only compiled if the appropriate subsystem is enabled
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
406 #endif /* SDL_CDROM_FREEBSD */ |