1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * msdos.c                                                  *
12 ***********************************************************/
13 
14 #include "system.h"
15 
16 
17 #if defined(PLATFORM_MSDOS)
18 
19 #include "sound.h"
20 #include "joystick.h"
21 #include "misc.h"
22 #include "setup.h"
23 #include "pcx.h"
24 
25 #define AllegroDefaultScreen() (display->screens[display->default_screen])
26 
27 /* allegro driver declarations */
28 DECLARE_GFX_DRIVER_LIST(GFX_DRIVER_VBEAF GFX_DRIVER_VESA2L GFX_DRIVER_VESA1)
29 DECLARE_COLOR_DEPTH_LIST(COLOR_DEPTH_8)
30 DECLARE_DIGI_DRIVER_LIST(DIGI_DRIVER_SB)
31 DECLARE_MIDI_DRIVER_LIST()
32 DECLARE_JOYSTICK_DRIVER_LIST(JOYSTICK_DRIVER_STANDARD)
33 
34 /* allegro global variables */
35 extern volatile int key_shifts;
36 extern int num_joysticks;
37 extern JOYSTICK_INFO joy[];
38 extern int i_love_bill;
39 
40 /* internal variables of msdos.c */
41 static boolean keyboard_auto_repeat = TRUE;
42 static int key_press_state[MAX_SCANCODES];
43 static XEvent event_buffer[MAX_EVENT_BUFFER];
44 static int pending_events;
45 static boolean joystick_event;
46 static boolean mouse_installed = FALSE;
47 static int last_mouse_pos;
48 static int last_mouse_b;
49 static int last_joystick_state;
50 static BITMAP* video_bitmap;
51 
52 static RGB global_colormap[MAX_COLORS];
53 static int global_colormap_entries_used = 0;
54 
55 boolean wait_for_vsync;
56 
57 static BITMAP *Read_PCX_to_AllegroBitmap(char *);
58 
allegro_init_drivers()59 static void allegro_init_drivers()
60 {
61   int i;
62 
63   for (i = 0; i < MAX_EVENT_BUFFER; i++)
64     event_buffer[i].type = 0;
65 
66   for (i = 0; i < MAX_SCANCODES; i++)
67     key_press_state[i] = KeyReleaseMask;
68 
69   last_mouse_pos = mouse_pos;
70   last_mouse_b = 0;
71 
72   pending_events = 0;
73   clear_keybuf();
74 
75   /* enable Windows friendly timer mode (already default under Windows) */
76   i_love_bill = TRUE;
77 
78   install_keyboard();
79   install_timer();
80   if (install_mouse() > 0)
81     mouse_installed = TRUE;
82 
83   last_joystick_state = 0;
84   joystick_event = FALSE;
85 }
86 
allegro_init_audio()87 static boolean allegro_init_audio()
88 {
89   reserve_voices(NUM_MIXER_CHANNELS, 0);
90 
91   if (install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL) == -1)
92     if (install_sound(DIGI_SB, MIDI_NONE, NULL) == -1)
93       return FALSE;
94 
95   return TRUE;
96 }
97 
hide_mouse(Display * display,int x,int y,unsigned int width,unsigned int height)98 static boolean hide_mouse(Display *display, int x, int y,
99 			  unsigned int width, unsigned int height)
100 {
101   if (mouse_x + display->mouse_ptr->w < x || mouse_x > x + width)
102     return FALSE;
103   if (mouse_y + display->mouse_ptr->h < y || mouse_y > y + height)
104     return FALSE;
105 
106   show_mouse(NULL);
107 
108   return TRUE;
109 }
110 
unhide_mouse(Display * display)111 static void unhide_mouse(Display *display)
112 {
113   if (mouse_installed)
114     show_mouse(video_bitmap);
115 }
116 
ScancodeToKeySym(byte scancode)117 static KeySym ScancodeToKeySym(byte scancode)
118 {
119   switch(scancode)
120   {
121     case KEY_ESC:		return XK_Escape;
122     case KEY_1:			return XK_1;
123     case KEY_2:			return XK_2;
124     case KEY_3:			return XK_3;
125     case KEY_4:			return XK_4;
126     case KEY_5:			return XK_5;
127     case KEY_6:			return XK_6;
128     case KEY_7:			return XK_7;
129     case KEY_8:			return XK_8;
130     case KEY_9:			return XK_9;
131     case KEY_0:			return XK_0;
132     case KEY_MINUS:		return XK_minus;
133     case KEY_EQUALS:		return XK_equal;
134     case KEY_BACKSPACE:		return XK_BackSpace;
135     case KEY_TAB:		return XK_Tab;
136     case KEY_Q:			return XK_q;
137     case KEY_W:			return XK_w;
138     case KEY_E:			return XK_e;
139     case KEY_R:			return XK_r;
140     case KEY_T:			return XK_t;
141     case KEY_Y:			return XK_y;
142     case KEY_U:			return XK_u;
143     case KEY_I:			return XK_i;
144     case KEY_O:			return XK_o;
145     case KEY_P:			return XK_p;
146     case KEY_OPENBRACE:		return XK_braceleft;
147     case KEY_CLOSEBRACE:	return XK_braceright;
148     case KEY_ENTER:		return XK_Return;
149     case KEY_LCONTROL:		return XK_Control_L;
150     case KEY_A:			return XK_a;
151     case KEY_S:			return XK_s;
152     case KEY_D:			return XK_d;
153     case KEY_F:			return XK_f;
154     case KEY_G:			return XK_g;
155     case KEY_H:			return XK_h;
156     case KEY_J:			return XK_j;
157     case KEY_K:			return XK_k;
158     case KEY_L:			return XK_l;
159     case KEY_COLON:		return XK_colon;
160     case KEY_QUOTE:		return XK_apostrophe;
161     case KEY_TILDE:		return XK_asciitilde;
162     case KEY_LSHIFT:		return XK_Shift_L;
163     case KEY_BACKSLASH:		return XK_backslash;
164     case KEY_Z:			return XK_z;
165     case KEY_X:			return XK_x;
166     case KEY_C:			return XK_c;
167     case KEY_V:			return XK_v;
168     case KEY_B:			return XK_b;
169     case KEY_N:			return XK_n;
170     case KEY_M:			return XK_m;
171     case KEY_COMMA:		return XK_comma;
172     case KEY_STOP:		return XK_period;
173     case KEY_SLASH:		return XK_slash;
174     case KEY_RSHIFT:		return XK_Shift_R;
175     case KEY_ASTERISK:		return XK_KP_Multiply;
176     case KEY_ALT:		return XK_Alt_L;
177     case KEY_SPACE:		return XK_space;
178     case KEY_CAPSLOCK:		return XK_Caps_Lock;
179     case KEY_F1:		return XK_F1;
180     case KEY_F2:		return XK_F2;
181     case KEY_F3:		return XK_F3;
182     case KEY_F4:		return XK_F4;
183     case KEY_F5:		return XK_F5;
184     case KEY_F6:		return XK_F6;
185     case KEY_F7:		return XK_F7;
186     case KEY_F8:		return XK_F8;
187     case KEY_F9:		return XK_F9;
188     case KEY_F10:		return XK_F10;
189     case KEY_NUMLOCK:		return XK_Num_Lock;
190     case KEY_SCRLOCK:		return XK_Scroll_Lock;
191     case KEY_HOME:		return XK_Home;
192     case KEY_UP:		return XK_Up;
193     case KEY_PGUP:		return XK_Page_Up;
194     case KEY_MINUS_PAD:		return XK_KP_Subtract;
195     case KEY_LEFT:		return XK_Left;
196     case KEY_5_PAD:		return XK_KP_5;
197     case KEY_RIGHT:		return XK_Right;
198     case KEY_PLUS_PAD:		return XK_KP_Add;
199     case KEY_END:		return XK_End;
200     case KEY_DOWN:		return XK_Down;
201     case KEY_PGDN:		return XK_Page_Down;
202     case KEY_INSERT:		return XK_Insert;
203     case KEY_DEL:		return XK_Delete;
204     case KEY_PRTSCR:		return XK_Print;
205     case KEY_F11:		return XK_F11;
206     case KEY_F12:		return XK_F12;
207     case KEY_LWIN:		return XK_Meta_L;
208     case KEY_RWIN:		return XK_Meta_R;
209     case KEY_MENU:		return XK_Menu;
210     case KEY_PAD:		return XK_VoidSymbol;
211     case KEY_RCONTROL:		return XK_Control_R;
212     case KEY_ALTGR:		return XK_Alt_R;
213     case KEY_SLASH2:		return XK_KP_Divide;
214     case KEY_PAUSE:		return XK_Pause;
215 
216     case NEW_KEY_BACKSLASH:	return XK_backslash;
217     case NEW_KEY_1_PAD:		return XK_KP_1;
218     case NEW_KEY_2_PAD:		return XK_KP_2;
219     case NEW_KEY_3_PAD:		return XK_KP_3;
220     case NEW_KEY_4_PAD:		return XK_KP_4;
221     case NEW_KEY_5_PAD:		return XK_KP_5;
222     case NEW_KEY_6_PAD:		return XK_KP_6;
223     case NEW_KEY_7_PAD:		return XK_KP_7;
224     case NEW_KEY_8_PAD:		return XK_KP_8;
225     case NEW_KEY_9_PAD:		return XK_KP_9;
226     case NEW_KEY_0_PAD:		return XK_KP_0;
227     case NEW_KEY_STOP_PAD:	return XK_KP_Separator;
228     case NEW_KEY_EQUALS_PAD:	return XK_KP_Equal;
229     case NEW_KEY_SLASH_PAD:	return XK_KP_Divide;
230     case NEW_KEY_ASTERISK_PAD:	return XK_KP_Multiply;
231     case NEW_KEY_ENTER_PAD:	return XK_KP_Enter;
232 
233     default:			return XK_VoidSymbol;
234   }
235 }
236 
AllegroAllocColorCell(int r,int g,int b)237 Pixel AllegroAllocColorCell(int r, int g, int b)
238 {
239   byte pixel_mapping = 0;
240   int i;
241 
242   r >>= 10;
243   g >>= 10;
244   b >>= 10;
245 
246   /* try to use existing colors from the global colormap */
247   for (i = 0; i < global_colormap_entries_used; i++)
248   {
249     if (r == global_colormap[i].r &&
250 	g == global_colormap[i].g &&
251 	b == global_colormap[i].b)		/* color found */
252     {
253       pixel_mapping = i;
254       break;
255     }
256   }
257 
258   if (i == global_colormap_entries_used)	/* color not found */
259   {
260     if (global_colormap_entries_used < MAX_COLORS)
261       global_colormap_entries_used++;
262 
263     i = global_colormap_entries_used - 1;
264 
265     global_colormap[i].r = r;
266     global_colormap[i].g = g;
267     global_colormap[i].b = b;
268 
269     set_palette(global_colormap);
270 
271     pixel_mapping = i;
272   }
273 
274   return pixel_mapping;
275 }
276 
XMapWindow(Display * display,Window window)277 void XMapWindow(Display *display, Window window)
278 {
279   int x, y;
280   unsigned int width, height;
281   boolean mouse_off;
282 
283   x = AllegroDefaultScreen().x;
284   y = AllegroDefaultScreen().y;
285   width = AllegroDefaultScreen().width;
286   height = AllegroDefaultScreen().height;
287 
288   mouse_off = hide_mouse(display, x, y, width, height);
289   blit((BITMAP *)window, video_bitmap, 0, 0, x, y, width, height);
290 
291   if (mouse_off)
292     unhide_mouse(display);
293 }
294 
XOpenDisplay(char * display_name)295 Display *XOpenDisplay(char *display_name)
296 {
297   Screen *screen;
298   Display *display;
299   BITMAP *mouse_bitmap = NULL;
300   char *mouse_filename = getCustomImageFilename(program.msdos_cursor_filename);
301 
302   if ((mouse_bitmap = Read_PCX_to_AllegroBitmap(mouse_filename)) == NULL)
303     return NULL;
304 
305   screen = malloc(sizeof(Screen));
306   display = malloc(sizeof(Display));
307 
308   screen[0].cmap = 0;
309   screen[0].root = 0;
310   screen[0].white_pixel = AllegroAllocColorCell(0xFFFF, 0xFFFF, 0xFFFF);
311   screen[0].black_pixel = AllegroAllocColorCell(0x0000, 0x0000, 0x0000);
312   screen[0].video_bitmap = NULL;
313 
314   display->default_screen = 0;
315   display->screens = screen;
316   display->mouse_ptr = mouse_bitmap;
317 
318   allegro_init();
319   allegro_init_drivers();
320   set_color_depth(8);
321 
322   /* force Windows 95 to switch to fullscreen mode */
323   set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0);
324   rest(200);
325   set_gfx_mode(GFX_AUTODETECT, XRES, YRES, 0, 0);
326 
327   return display;
328 }
329 
XCreateSimpleWindow(Display * display,Window parent,int x,int y,unsigned int width,unsigned int height,unsigned int border_width,unsigned int border,unsigned int background)330 Window XCreateSimpleWindow(Display *display, Window parent, int x, int y,
331 			   unsigned int width, unsigned int height,
332 			   unsigned int border_width, unsigned int border,
333 			   unsigned int background)
334 {
335   video_bitmap = create_video_bitmap(XRES, YRES);
336   clear_to_color(video_bitmap, background);
337 
338   AllegroDefaultScreen().video_bitmap = video_bitmap;
339   AllegroDefaultScreen().x = x;
340   AllegroDefaultScreen().y = y;
341   AllegroDefaultScreen().width = XRES;
342   AllegroDefaultScreen().height = YRES;
343 
344   set_mouse_sprite(display->mouse_ptr);
345 
346 #if 0
347   set_mouse_sprite_focus(1, 1);
348 #endif
349 
350   set_mouse_speed(1, 1);
351   set_mouse_range(AllegroDefaultScreen().x + 1,
352 		  AllegroDefaultScreen().y + 1,
353 		  AllegroDefaultScreen().x + video.width + 1,
354 		  AllegroDefaultScreen().y + video.height + 1);
355 
356   show_video_bitmap(video_bitmap);
357 
358   return (Window)video_bitmap;
359 }
360 
XStringListToTextProperty(char ** list,int count,XTextProperty * text_prop_return)361 Status XStringListToTextProperty(char **list, int count,
362 				 XTextProperty *text_prop_return)
363 {
364   char *string;
365 
366   if (count >= 1)
367   {
368     string = malloc(strlen(list[0] + 1));
369     strcpy(string, list[0]);
370     text_prop_return->value = (unsigned char *)string;
371     return 1;
372   }
373   else
374     text_prop_return = NULL;
375 
376   return 0;
377 }
378 
XFree(void * data)379 void XFree(void *data)
380 {
381   checked_free(data);
382 }
383 
XCreateGC(Display * display,Drawable d,unsigned int value_mask,XGCValues * values)384 GC XCreateGC(Display *display, Drawable d, unsigned int value_mask,
385 	     XGCValues *values)
386 {
387   XGCValues *gcv;
388   gcv = malloc(sizeof(XGCValues));
389   gcv->foreground = values->foreground;
390   gcv->background = values->background;
391   gcv->graphics_exposures = values->graphics_exposures;
392   gcv->clip_mask = values->clip_mask;
393   gcv->clip_x_origin = values->clip_x_origin;
394   gcv->clip_y_origin = values->clip_y_origin;
395   gcv->value_mask = value_mask;
396   return (GC)gcv;
397 }
398 
XSetClipMask(Display * display,GC gc,Pixmap pixmap)399 void XSetClipMask(Display *display, GC gc, Pixmap pixmap)
400 {
401   XGCValues *gcv = (XGCValues *)gc;
402 
403   gcv->clip_mask = pixmap;
404   gcv->value_mask |= GCClipMask;
405 }
406 
XSetClipOrigin(Display * display,GC gc,int x,int y)407 void XSetClipOrigin(Display *display, GC gc, int x, int y)
408 {
409   XGCValues *gcv = (XGCValues *)gc;
410 
411   gcv->clip_x_origin = x;
412   gcv->clip_x_origin = y;
413 }
414 
XFillRectangle(Display * display,Drawable d,GC gc,int x,int y,unsigned int width,unsigned int height)415 void XFillRectangle(Display *display, Drawable d, GC gc, int x, int y,
416 		    unsigned int width, unsigned int height)
417 {
418   boolean mouse_off = FALSE;
419 
420   if ((BITMAP *)d == video_bitmap)
421   {
422     x += AllegroDefaultScreen().x;
423     y += AllegroDefaultScreen().y;
424     freeze_mouse_flag = TRUE;
425     mouse_off = hide_mouse(display, x, y, width, height);
426   }
427 
428   rectfill((BITMAP *)d, x, y, x + width - 1, y + height - 1,
429 	   ((XGCValues *)gc)->foreground);
430 
431   if (mouse_off)
432     unhide_mouse(display);
433 
434   freeze_mouse_flag = FALSE;
435 }
436 
XCreatePixmap(Display * display,Drawable d,unsigned int width,unsigned int height,unsigned int depth)437 Pixmap XCreatePixmap(Display *display, Drawable d, unsigned int width,
438 		     unsigned int height, unsigned int depth)
439 {
440   BITMAP *bitmap = NULL;
441 
442   if (gfx_capabilities & GFX_HW_VRAM_BLIT &&
443       width == gfx.scrollbuffer_width && height == gfx.scrollbuffer_height)
444     bitmap = create_video_bitmap(width, height);
445 
446   if (bitmap == NULL)
447     bitmap = create_bitmap(width, height);
448 
449   return (Pixmap)bitmap;
450 }
451 
XSync(Display * display,Bool discard_events)452 void XSync(Display *display, Bool discard_events)
453 {
454   wait_for_vsync = TRUE;
455 }
456 
XCopyArea(Display * display,Drawable src,Drawable dest,GC gc,int src_x,int src_y,unsigned int width,unsigned int height,int dest_x,int dest_y)457 inline void XCopyArea(Display *display, Drawable src, Drawable dest, GC gc,
458 		      int src_x, int src_y,
459 		      unsigned int width, unsigned int height,
460 		      int dest_x, int dest_y)
461 {
462   boolean mouse_off = FALSE;
463 
464   if ((BITMAP *)src == video_bitmap)
465   {
466     src_x += AllegroDefaultScreen().x;
467     src_y += AllegroDefaultScreen().y;
468   }
469 
470   if ((BITMAP *)dest == video_bitmap)
471   {
472     dest_x += AllegroDefaultScreen().x;
473     dest_y += AllegroDefaultScreen().y;
474     freeze_mouse_flag = TRUE;
475     mouse_off = hide_mouse(display, dest_x, dest_y, width, height);
476   }
477 
478   if (wait_for_vsync)
479   {
480     wait_for_vsync = FALSE;
481     vsync();
482   }
483 
484   if (((XGCValues *)gc)->value_mask & GCClipMask)
485     masked_blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y,
486 		width, height);
487   else
488     blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y,
489 	 width, height);
490 
491   if (mouse_off)
492     unhide_mouse(display);
493 
494   freeze_mouse_flag = FALSE;
495 }
496 
Image_to_AllegroBitmap(Image * image)497 static BITMAP *Image_to_AllegroBitmap(Image *image)
498 {
499   BITMAP *bitmap;
500   byte *src_ptr = image->data;
501   byte pixel_mapping[MAX_COLORS];
502   unsigned int depth = 8;
503   int i, x, y;
504 
505   if (image->type == IMAGETYPE_TRUECOLOR && depth == 8)
506     Error(ERR_EXIT, "cannot handle true-color images on 8-bit display");
507 
508   /* allocate new allegro bitmap structure */
509   if ((bitmap = create_bitmap_ex(depth, image->width, image->height)) == NULL)
510   {
511     errno_pcx = PCX_NoMemory;
512     return NULL;
513   }
514 
515   clear(bitmap);
516 
517   /* try to use existing colors from the global colormap */
518   for (i = 0; i < MAX_COLORS; i++)
519   {
520     if (!image->rgb.color_used[i])
521       continue;
522 
523     pixel_mapping[i] = AllegroAllocColorCell(image->rgb.red[i],
524 					     image->rgb.green[i],
525 					     image->rgb.blue[i]);
526   }
527 
528   /* copy bitmap data */
529   for (y = 0; y < image->height; y++)
530     for (x = 0; x < image->width; x++)
531       putpixel(bitmap, x, y, pixel_mapping[*src_ptr++]);
532 
533   return bitmap;
534 }
535 
Read_PCX_to_AllegroBitmap(char * filename)536 static BITMAP *Read_PCX_to_AllegroBitmap(char *filename)
537 {
538   BITMAP *bitmap;
539   Image *image;
540 
541   /* read the graphic file in PCX format to internal image structure */
542   if ((image = Read_PCX_to_Image(filename)) == NULL)
543     return NULL;
544 
545   /* convert internal image structure to allegro bitmap structure */
546   if ((bitmap = Image_to_AllegroBitmap(image)) == NULL)
547     return NULL;
548 
549   set_palette(global_colormap);
550 
551   return bitmap;
552 }
553 
Read_PCX_to_Pixmap(Display * display,Window window,GC gc,char * filename,Pixmap * pixmap,Pixmap * pixmap_mask)554 int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
555 		       Pixmap *pixmap, Pixmap *pixmap_mask)
556 {
557   BITMAP *bitmap;
558 
559   if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
560     return errno_pcx;
561 
562   *pixmap = (Pixmap)bitmap;
563 
564   /* pixmap_mask will never be used in Allegro (which uses masked_blit()),
565      so use non-NULL dummy pointer to empty Pixmap */
566   *pixmap_mask = (Pixmap)DUMMY_MASK;
567 
568   return PCX_Success;
569 }
570 
XReadBitmapFile(Display * display,Drawable d,char * filename,unsigned int * width_return,unsigned int * height_return,Pixmap * bitmap_return,int * x_hot_return,int * y_hot_return)571 int XReadBitmapFile(Display *display, Drawable d, char *filename,
572 		    unsigned int *width_return, unsigned int *height_return,
573 		    Pixmap *bitmap_return,
574 		    int *x_hot_return, int *y_hot_return)
575 {
576   BITMAP *bitmap;
577 
578   if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
579     return BitmapOpenFailed;
580 
581   *width_return = bitmap->w;
582   *height_return = bitmap->h;
583   *x_hot_return = -1;
584   *y_hot_return = -1;
585   *bitmap_return = (Pixmap)bitmap;
586 
587   return BitmapSuccess;
588 }
589 
XFreePixmap(Display * display,Pixmap pixmap)590 void XFreePixmap(Display *display, Pixmap pixmap)
591 {
592   if (pixmap != DUMMY_MASK &&
593       (is_memory_bitmap((BITMAP *)pixmap) ||
594        is_screen_bitmap((BITMAP *)pixmap)))
595     destroy_bitmap((BITMAP *)pixmap);
596 }
597 
XFreeGC(Display * display,GC gc)598 void XFreeGC(Display *display, GC gc)
599 {
600   XGCValues *gcv = (XGCValues *)gc;
601 
602   checked_free(gcv);
603 }
604 
XUnmapWindow(Display * display,Window window)605 void XUnmapWindow(Display *display, Window window)
606 {
607 }
608 
XCloseDisplay(Display * display)609 void XCloseDisplay(Display *display)
610 {
611   BITMAP *bitmap = video_bitmap;
612 
613   if (is_screen_bitmap(bitmap))
614     destroy_bitmap(bitmap);
615 
616   checked_free(display->screens);
617   checked_free(display);
618 
619   /* return to text mode (or DOS box on Windows screen) */
620   set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
621 }
622 
XNextEvent(Display * display,XEvent * event_return)623 void XNextEvent(Display *display, XEvent *event_return)
624 {
625   while (!pending_events)
626     XPending(display);
627 
628   memcpy(event_return, &event_buffer[pending_events], sizeof(XEvent));
629   pending_events--;
630 }
631 
NewKeyEvent(int key_press_state,KeySym keysym)632 static void NewKeyEvent(int key_press_state, KeySym keysym)
633 {
634   XKeyEvent *xkey;
635 
636   if (pending_events >= MAX_EVENT_BUFFER)
637     return;
638 
639   pending_events++;
640   xkey = (XKeyEvent *)&event_buffer[pending_events];
641   xkey->type = key_press_state;
642   xkey->state = (unsigned int)keysym;
643 }
644 
645 #define HANDLE_RAW_KB_ALL_KEYS			0
646 #define HANDLE_RAW_KB_MODIFIER_KEYS_ONLY	1
647 
648 static int modifier_scancode[] =
649 {
650   KEY_LSHIFT,
651   KEY_RSHIFT,
652   KEY_LCONTROL,
653   KEY_RCONTROL,
654   KEY_ALT,
655   KEY_ALTGR,
656   KEY_LWIN,
657   KEY_RWIN,
658   KEY_CAPSLOCK,
659   KEY_NUMLOCK,
660   KEY_SCRLOCK,
661   -1
662 };
663 
HandleKeyboardRaw(int mode)664 static void HandleKeyboardRaw(int mode)
665 {
666   int i;
667 
668   for (i = 0; i < MAX_SCANCODES; i++)
669   {
670     int scancode, new_state, event_type;
671     char key_pressed;
672 
673     if (mode == HANDLE_RAW_KB_MODIFIER_KEYS_ONLY)
674     {
675       if ((scancode = modifier_scancode[i]) == -1)
676 	return;
677     }
678     else
679       scancode = i;
680 
681     key_pressed = key[scancode];
682     new_state = (key_pressed ? KeyPressMask : KeyReleaseMask);
683     event_type = (key_pressed ? KeyPress : KeyRelease);
684 
685     if (key_press_state[i] == new_state)	/* state not changed */
686       continue;
687 
688     key_press_state[i] = new_state;
689 
690     NewKeyEvent(event_type, ScancodeToKeySym(scancode));
691   }
692 }
693 
HandleKeyboardEvent()694 static void HandleKeyboardEvent()
695 {
696   if (keypressed())
697   {
698     int key_info = readkey();
699     int scancode = (key_info >> 8);
700     int ascii = (key_info & 0xff);
701     KeySym keysym = ScancodeToKeySym(scancode);
702 
703     if (scancode == KEY_PAD)
704     {
705       /* keys on the numeric keypad return just scancode 'KEY_PAD'
706 	 for some reason, so we must handle them separately */
707 
708       if (ascii >= '0' && ascii <= '9')
709 	keysym = XK_KP_0 + (KeySym)(ascii - '0');
710       else if (ascii == '.')
711 	keysym = XK_KP_Separator;
712     }
713     else if (ascii >= ' ' && ascii <= 'Z')
714       keysym = XK_space + (KeySym)(ascii - ' ');
715     else if (ascii == '^')
716       keysym = XK_asciicircum;
717     else if (ascii == '_')
718       keysym = XK_underscore;
719     else if (ascii == '�')
720       keysym = XK_Adiaeresis;
721     else if (ascii == '�')
722       keysym = XK_Odiaeresis;
723     else if (ascii == '�')
724       keysym = XK_Udiaeresis;
725     else if (ascii == '�')
726       keysym = XK_adiaeresis;
727     else if (ascii == '�')
728       keysym = XK_odiaeresis;
729     else if (ascii == '�')
730       keysym = XK_udiaeresis;
731     else if (ascii == '�')
732       keysym = XK_ssharp;
733 
734     NewKeyEvent(KeyPress, keysym);
735   }
736   else if (key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG))
737   {
738     /* the allegro function keypressed() does not give us single pressed
739        modifier keys, so we must detect them with the internal global
740        allegro variable 'key_shifts' and then handle them separately */
741 
742     HandleKeyboardRaw(HANDLE_RAW_KB_MODIFIER_KEYS_ONLY);
743   }
744 }
745 
XPending(Display * display)746 int XPending(Display *display)
747 {
748   XButtonEvent *xbutton;
749   XMotionEvent *xmotion;
750   int i;
751 
752   /* When using 'HandleKeyboardRaw()', keyboard input is also stored in
753      the allegro keyboard input buffer and would be available a second
754      time by calling 'HandleKeyboardEvent()'. To avoid double keyboard
755      events, the allegro function 'clear_keybuf()' must be called each
756      time when switching from calling 'HandleKeyboardRaw()' to calling
757      'HandleKeyboardEvent()' to get keyboard input, which is actually
758      done by 'XAutoRepeatOn()' which sets keyboard_auto_repeat to TRUE. */
759 
760   /* keyboard event */
761   if (keyboard_auto_repeat)
762     HandleKeyboardEvent();
763   else
764     HandleKeyboardRaw(HANDLE_RAW_KB_ALL_KEYS);
765 
766   /* mouse motion event */
767   if (mouse_pos != last_mouse_pos)
768   {
769     last_mouse_pos = mouse_pos;
770     pending_events++;
771     xmotion = (XMotionEvent *)&event_buffer[pending_events];
772     xmotion->type = MotionNotify;
773     xmotion->x = mouse_x - AllegroDefaultScreen().x;
774     xmotion->y = mouse_y - AllegroDefaultScreen().y;
775   }
776 
777   /* mouse button event */
778   if (mouse_b != last_mouse_b)
779   {
780     for (i = 0; i < 3; i++)	/* check all three mouse buttons */
781     {
782       int bitmask = (1 << i);
783 
784       if ((last_mouse_b & bitmask) != (mouse_b & bitmask))
785       {
786 	int mapping[3] = { 1, 3, 2 };
787 
788 	pending_events++;
789         xbutton = (XButtonEvent *)&event_buffer[pending_events];
790         xbutton->type = (mouse_b & bitmask ? ButtonPress : ButtonRelease);
791         xbutton->button = mapping[i];
792 	xbutton->x = mouse_x - AllegroDefaultScreen().x;
793 	xbutton->y = mouse_y - AllegroDefaultScreen().y;
794       }
795     }
796     last_mouse_b = mouse_b;
797   }
798 
799   return pending_events;
800 }
801 
XLookupKeysym(XKeyEvent * key_event,int index)802 KeySym XLookupKeysym(XKeyEvent *key_event, int index)
803 {
804   return key_event->state;
805 }
806 
XLookupString(XKeyEvent * key_event,char * buffer,int buffer_size,KeySym * key,XComposeStatus * compose)807 int XLookupString(XKeyEvent *key_event, char *buffer, int buffer_size,
808 		  KeySym *key, XComposeStatus *compose)
809 {
810   *key = key_event->state;
811   return 0;
812 }
813 
XSetForeground(Display * display,GC gc,unsigned int pixel)814 void XSetForeground(Display *display, GC gc, unsigned int pixel)
815 {
816   XGCValues *gcv = (XGCValues *)gc;
817 
818   gcv->foreground = pixel;
819 }
820 
XDrawLine(Display * display,Drawable d,GC gc,int x1,int y1,int x2,int y2)821 void XDrawLine(Display *display, Drawable d, GC gc,
822 	       int x1, int y1, int x2, int y2)
823 {
824   XGCValues *gcv = (XGCValues *)gc;
825   boolean mouse_off = FALSE;
826 
827   if ((BITMAP *)d == video_bitmap)
828   {
829     x1 += AllegroDefaultScreen().x;
830     y1 += AllegroDefaultScreen().y;
831     x2 += AllegroDefaultScreen().x;
832     y2 += AllegroDefaultScreen().y;
833     freeze_mouse_flag = TRUE;
834     mouse_off = hide_mouse(display, MIN(x1, x2), MIN(y1, y2),
835 			   MAX(x1, x2) - MIN(x1, x2),
836 			   MAX(y1, y2) - MIN(y1, y2));
837   }
838 
839   line((BITMAP *)d, x1, y1, x2, y2, gcv->foreground);
840 
841   if (mouse_off)
842     unhide_mouse(display);
843 
844   freeze_mouse_flag = FALSE;
845 }
846 
XDestroyImage(XImage * ximage)847 void XDestroyImage(XImage *ximage)
848 {
849 }
850 
XDestroyWindow(Display * display,Window window)851 void XDestroyWindow(Display *display, Window window)
852 {
853 }
854 
XQueryPointer(Display * display,Window window,Window * root,Window * child,int * root_x,int * root_y,int * win_x,int * win_y,unsigned int * mask)855 Bool XQueryPointer(Display *display, Window window,
856 		   Window *root, Window *child, int *root_x, int *root_y,
857 		   int *win_x, int *win_y, unsigned int *mask)
858 {
859   *win_x = mouse_x - AllegroDefaultScreen().x;
860   *win_y = mouse_y - AllegroDefaultScreen().y;
861 
862   return True;
863 }
864 
XAutoRepeatOn(Display * display)865 void XAutoRepeatOn(Display *display)
866 {
867   keyboard_auto_repeat = TRUE;
868   clear_keybuf();
869 }
870 
XAutoRepeatOff(Display * display)871 void XAutoRepeatOff(Display *display)
872 {
873   keyboard_auto_repeat = FALSE;
874 }
875 
AllegroDrawLine(Drawable d,int from_x,int from_y,int to_x,int to_y,Pixel color)876 void AllegroDrawLine(Drawable d, int from_x, int from_y, int to_x, int to_y,
877 		     Pixel color)
878 {
879   boolean mouse_off = FALSE;
880 
881   if ((BITMAP *)d == video_bitmap)
882   {
883     int dx = AllegroDefaultScreen().x;
884     int dy = AllegroDefaultScreen().y;
885     int x1, y1, x2, y2;
886 
887     from_x += dx;
888     from_y += dy;
889     to_x += dx;
890     to_y += dy;
891 
892     x1 = (from_x < to_x ? from_x : to_x);
893     y1 = (from_y < to_y ? from_y : to_y);
894     x2 = (from_x < to_x ? to_x : from_x);
895     y2 = (from_y < to_y ? to_y : from_y);
896 
897     freeze_mouse_flag = TRUE;
898     mouse_off = hide_mouse(display, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
899   }
900 
901   line((BITMAP *)d, from_x, from_y, to_x, to_y, color);
902 
903   if (mouse_off)
904     unhide_mouse(display);
905 
906   freeze_mouse_flag = FALSE;
907 }
908 
AllegroGetPixel(Drawable d,int x,int y)909 Pixel AllegroGetPixel(Drawable d, int x, int y)
910 {
911   return getpixel((BITMAP *)d, x, y);
912 }
913 
AllegroZoomBitmap(Drawable src,Drawable dst,int src_width,int src_height,int dst_width,int dst_height)914 void AllegroZoomBitmap(Drawable src, Drawable dst,
915 		       int src_width, int src_height,
916 		       int dst_width, int dst_height)
917 {
918   stretch_blit((BITMAP *)src, (BITMAP *)dst,
919 	       0, 0, src_width, src_height, 0, 0, dst_width, dst_height);
920 }
921 
MSDOSOpenAudio(void)922 void MSDOSOpenAudio(void)
923 {
924   if (allegro_init_audio())
925   {
926     audio.sound_available = TRUE;
927     audio.music_available = TRUE;
928     audio.loops_available = TRUE;
929     audio.sound_enabled = TRUE;
930 
931     audio.num_channels = NUM_MIXER_CHANNELS;
932     audio.music_channel = MUSIC_CHANNEL;
933     audio.first_sound_channel = FIRST_SOUND_CHANNEL;
934 
935     Mixer_InitChannels();
936   }
937 }
938 
MSDOSCloseAudio(void)939 void MSDOSCloseAudio(void)
940 {
941   /* nothing to be done here */
942 }
943 
NetworkServer(int port,int serveronly)944 void NetworkServer(int port, int serveronly)
945 {
946   Error(ERR_WARN, "networking not supported in DOS version");
947 }
948 
949 
950 /* ========================================================================= */
951 /* joystick functions                                                        */
952 /* ========================================================================= */
953 
MSDOSInitJoysticks()954 void MSDOSInitJoysticks()
955 {
956   int i;
957 
958   /* start from scratch */
959   remove_joystick();
960 
961   /* try to access two joysticks; if that fails, try to access just one */
962   if (install_joystick(JOY_TYPE_2PADS) == 0 ||
963       install_joystick(JOY_TYPE_AUTODETECT) == 0)
964     joystick.status = JOYSTICK_ACTIVATED;
965 
966   for (i = 0; i < MAX_PLAYERS; i++)
967   {
968     char *device_name = setup.input[i].joy.device_name;
969     int joystick_nr = getJoystickNrFromDeviceName(device_name);
970 
971     if (joystick_nr >= num_joysticks)
972       joystick_nr = -1;
973 
974     /* misuse joystick file descriptor variable to store joystick number */
975     joystick.fd[i] = joystick_nr;
976   }
977 }
978 
MSDOSReadJoystick(int nr,int * x,int * y,boolean * b1,boolean * b2)979 boolean MSDOSReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
980 {
981   /* the allegro global variable 'num_joysticks' contains the number
982      of joysticks found at initialization under MS-DOS / Windows */
983 
984   if (nr < 0 || nr >= num_joysticks)
985     return FALSE;
986 
987   poll_joystick();
988 
989   if (x != NULL)
990     *x = joy[nr].stick[0].axis[0].pos;
991   if (y != NULL)
992     *y = joy[nr].stick[0].axis[1].pos;
993 
994   if (b1 != NULL)
995     *b1 = joy[nr].button[0].b;
996   if (b2 != NULL)
997     *b2 = joy[nr].button[1].b;
998 
999   return TRUE;
1000 }
1001 
1002 #endif /* PLATFORM_MSDOS */
1003