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