782369c1560a7291f5e4df8b48cce25ce0ff6a88
[rocksndiamonds.git] / src / libgame / msdos.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
6 *        33659 Bielefeld-Senne                             *
7 *        Telefon: (0521) 493245                            *
8 *        eMail: aeglos@valinor.owl.de                      *
9 *               aeglos@uni-paderborn.de                    *
10 *               q99492@pbhrzx.uni-paderborn.de             *
11 *----------------------------------------------------------*
12 *  msdos.c                                                 *
13 ***********************************************************/
14
15 #include "libgame.h"
16
17 #if defined(PLATFORM_MSDOS)
18
19 #define AllegroDefaultScreen() (display->screens[display->default_screen])
20
21 /* allegro driver declarations */
22 DECLARE_GFX_DRIVER_LIST(GFX_DRIVER_VBEAF GFX_DRIVER_VESA2L GFX_DRIVER_VESA1)
23 DECLARE_COLOR_DEPTH_LIST(COLOR_DEPTH_8)
24 DECLARE_DIGI_DRIVER_LIST(DIGI_DRIVER_SB)
25 DECLARE_MIDI_DRIVER_LIST()
26 DECLARE_JOYSTICK_DRIVER_LIST(JOYSTICK_DRIVER_STANDARD)
27
28 /* allegro global variables */
29 extern volatile int key_shifts;
30 extern int num_joysticks;
31 extern JOYSTICK_INFO joy[];
32 extern int i_love_bill;
33
34 /* internal variables of msdos.c */
35 static boolean keyboard_auto_repeat = TRUE;
36 static int key_press_state[MAX_SCANCODES];
37 static XEvent event_buffer[MAX_EVENT_BUFFER];
38 static int pending_events;
39 static boolean joystick_event;
40 static boolean mouse_installed = FALSE;
41 static int last_mouse_pos;
42 static int last_mouse_b;
43 static int last_joystick_state;
44 static BITMAP* video_bitmap;
45
46 static RGB global_colormap[MAX_COLORS];
47 static int global_colormap_entries_used = 0;
48
49 boolean wait_for_vsync;
50
51 /*
52 extern int playing_sounds;
53 extern struct SoundControl playlist[MAX_SOUNDS_PLAYING];
54 extern struct SoundControl emptySoundControl;
55 */
56
57 static BITMAP *Read_PCX_to_AllegroBitmap(char *);
58
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
87 static boolean allegro_init_audio()
88 {
89   reserve_voices(MAX_SOUNDS_PLAYING, 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
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
111 static void unhide_mouse(Display *display)
112 {
113   if (mouse_installed)
114     show_mouse(video_bitmap);
115 }
116
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
237 void XMapWindow(Display *display, Window window)
238 {
239   int x, y;
240   unsigned int width, height;
241   boolean mouse_off;
242
243   x = AllegroDefaultScreen().x;
244   y = AllegroDefaultScreen().y;
245   width = AllegroDefaultScreen().width;
246   height = AllegroDefaultScreen().height;
247
248   mouse_off = hide_mouse(display, x, y, width, height);
249   blit((BITMAP *)window, video_bitmap, 0, 0, x, y, width, height);
250
251   if (mouse_off)
252     unhide_mouse(display);
253 }
254
255 static unsigned long AllocColorCell(int r, int g, int b)
256 {
257   byte pixel_mapping = 0;
258   int i;
259
260   r >>= 10;
261   g >>= 10;
262   b >>= 10;
263
264   /* try to use existing colors from the global colormap */
265   for (i=0; i<global_colormap_entries_used; i++)
266   {
267     if (r == global_colormap[i].r &&
268         g == global_colormap[i].g &&
269         b == global_colormap[i].b)              /* color found */
270     {
271       pixel_mapping = i;
272       break;
273     }
274   }
275
276   if (i == global_colormap_entries_used)        /* color not found */
277   {
278     if (global_colormap_entries_used < MAX_COLORS)
279       global_colormap_entries_used++;
280
281     global_colormap[i].r = r;
282     global_colormap[i].g = g;
283     global_colormap[i].b = b;
284
285     pixel_mapping = i;
286   }
287
288   return pixel_mapping;
289 }
290
291 Display *XOpenDisplay(char *display_name)
292 {
293   Screen *screen;
294   Display *display;
295   BITMAP *mouse_bitmap = NULL;
296
297   mouse_bitmap = Read_PCX_to_AllegroBitmap(program.msdos_pointer_filename);
298   if (mouse_bitmap == NULL)
299     return NULL;
300
301   screen = malloc(sizeof(Screen));
302   display = malloc(sizeof(Display));
303
304   screen[0].cmap = 0;
305   screen[0].root = 0;
306 #if 0
307   screen[0].white_pixel = 0xFF;
308   screen[0].black_pixel = 0x00;
309 #else
310   screen[0].white_pixel = AllocColorCell(0xFFFF, 0xFFFF, 0xFFFF);
311   screen[0].black_pixel = AllocColorCell(0x0000, 0x0000, 0x0000);
312 #endif
313   screen[0].video_bitmap = NULL;
314
315   display->default_screen = 0;
316   display->screens = screen;
317   display->mouse_ptr = mouse_bitmap;
318
319   allegro_init();
320   allegro_init_drivers();
321   set_color_depth(8);
322
323   /* force Windows 95 to switch to fullscreen mode */
324   set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0);
325   rest(200);
326   set_gfx_mode(GFX_AUTODETECT, XRES, YRES, 0, 0);
327
328   return display;
329 }
330
331 Window XCreateSimpleWindow(Display *display, Window parent, int x, int y,
332                            unsigned int width, unsigned int height,
333                            unsigned int border_width, unsigned long border,
334                            unsigned long background)
335 {
336   video_bitmap = create_video_bitmap(XRES, YRES);
337   clear_to_color(video_bitmap, background);
338
339   AllegroDefaultScreen().video_bitmap = video_bitmap;
340   AllegroDefaultScreen().x = x;
341   AllegroDefaultScreen().y = y;
342   AllegroDefaultScreen().width = XRES;
343   AllegroDefaultScreen().height = YRES;
344
345   set_mouse_sprite(display->mouse_ptr);
346
347 #if 0
348   set_mouse_sprite_focus(1, 1);
349 #endif
350
351   set_mouse_speed(1, 1);
352   set_mouse_range(AllegroDefaultScreen().x + 1,
353                   AllegroDefaultScreen().y + 1,
354                   AllegroDefaultScreen().x + video.width + 1,
355                   AllegroDefaultScreen().y + video.height + 1);
356
357   show_video_bitmap(video_bitmap);
358
359   return (Window)video_bitmap;
360 }
361
362 Status XStringListToTextProperty(char **list, int count,
363                                  XTextProperty *text_prop_return)
364 {
365   char *string;
366
367   if (count >= 1)
368   {
369     string = malloc(strlen(list[0] + 1));
370     strcpy(string, list[0]);
371     text_prop_return->value = (unsigned char *)string;
372     return 1;
373   }
374   else
375     text_prop_return = NULL;
376
377   return 0;
378 }
379
380 void XFree(void *data)
381 {
382   if (data)
383     free(data);
384 }
385
386 GC XCreateGC(Display *display, Drawable d, unsigned long value_mask,
387              XGCValues *values)
388 {
389   XGCValues *gcv;
390   gcv = malloc(sizeof(XGCValues));
391   gcv->foreground = values->foreground;
392   gcv->background = values->background;
393   gcv->graphics_exposures = values->graphics_exposures;
394   gcv->clip_mask = values->clip_mask;
395   gcv->clip_x_origin = values->clip_x_origin;
396   gcv->clip_y_origin = values->clip_y_origin;
397   gcv->value_mask = value_mask;
398   return (GC)gcv;
399 }
400
401 void XSetClipMask(Display *display, GC gc, Pixmap pixmap)
402 {
403   XGCValues *gcv = (XGCValues *)gc;
404
405   gcv->clip_mask = pixmap;
406   gcv->value_mask |= GCClipMask;
407 }
408
409 void XSetClipOrigin(Display *display, GC gc, int x, int y)
410 {
411   XGCValues *gcv = (XGCValues *)gc;
412
413   gcv->clip_x_origin = x;
414   gcv->clip_x_origin = y;
415 }
416
417 void XFillRectangle(Display *display, Drawable d, GC gc, int x, int y,
418                     unsigned int width, unsigned int height)
419 {
420   boolean mouse_off = FALSE;
421
422   if ((BITMAP *)d == video_bitmap)
423   {
424     x += AllegroDefaultScreen().x;
425     y += AllegroDefaultScreen().y;
426     freeze_mouse_flag = TRUE;
427     mouse_off = hide_mouse(display, x, y, width, height);
428   }
429
430   rectfill((BITMAP *)d, x, y, x + width - 1, y + height - 1,
431            ((XGCValues *)gc)->foreground);
432
433   if (mouse_off)
434     unhide_mouse(display);
435
436   freeze_mouse_flag = FALSE;
437 }
438
439 Pixmap XCreatePixmap(Display *display, Drawable d, unsigned int width,
440                      unsigned int height, unsigned int depth)
441 {
442   BITMAP *bitmap = NULL;
443
444   if (gfx_capabilities & GFX_HW_VRAM_BLIT &&
445       width == video.scrollbuffer_width && height == video.scrollbuffer_height)
446     bitmap = create_video_bitmap(width, height);
447
448   if (bitmap == NULL)
449     bitmap = create_bitmap(width, height);
450
451   return (Pixmap)bitmap;
452 }
453
454 void XSync(Display *display, Bool discard_events)
455 {
456   wait_for_vsync = TRUE;
457 }
458
459 inline void XCopyArea(Display *display, Drawable src, Drawable dest, GC gc,
460                       int src_x, int src_y,
461                       unsigned int width, unsigned int height,
462                       int dest_x, int dest_y)
463 {
464   boolean mouse_off = FALSE;
465
466   if ((BITMAP *)src == video_bitmap)
467   {
468     src_x += AllegroDefaultScreen().x;
469     src_y += AllegroDefaultScreen().y;
470   }
471
472   if ((BITMAP *)dest == video_bitmap)
473   {
474     dest_x += AllegroDefaultScreen().x;
475     dest_y += AllegroDefaultScreen().y;
476     freeze_mouse_flag = TRUE;
477     mouse_off = hide_mouse(display, dest_x, dest_y, width, height);
478   }
479
480   if (wait_for_vsync)
481   {
482     wait_for_vsync = FALSE;
483     vsync();
484   }
485
486   if (((XGCValues *)gc)->value_mask & GCClipMask)
487     masked_blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y,
488                 width, height);
489   else
490     blit((BITMAP *)src, (BITMAP *)dest, src_x, src_y, dest_x, dest_y,
491          width, height);
492
493   if (mouse_off)
494     unhide_mouse(display);
495
496   freeze_mouse_flag = FALSE;
497 }
498
499 static BITMAP *Image_to_AllegroBitmap(Image *image)
500 {
501   BITMAP *bitmap;
502   byte *src_ptr = image->data;
503   byte pixel_mapping[MAX_COLORS];
504   unsigned int depth = 8;
505
506 #if 0
507   int i, j, x, y;
508 #else
509   int i, x, y;
510 #endif
511
512   /* allocate new allegro bitmap structure */
513   if ((bitmap = create_bitmap_ex(depth, image->width, image->height)) == NULL)
514   {
515     errno_pcx = PCX_NoMemory;
516     return NULL;
517   }
518
519   clear(bitmap);
520
521   /* try to use existing colors from the global colormap */
522   for (i=0; i<MAX_COLORS; i++)
523   {
524
525 #if 0
526     int r, g, b;
527 #endif
528
529     if (!image->rgb.color_used[i])
530       continue;
531
532
533 #if 0
534     r = image->rgb.red[i] >> 10;
535     g = image->rgb.green[i] >> 10;
536     b = image->rgb.blue[i] >> 10;
537
538     for (j=0; j<global_colormap_entries_used; j++)
539     {
540       if (r == global_colormap[j].r &&
541           g == global_colormap[j].g &&
542           b == global_colormap[j].b)            /* color found */
543       {
544         pixel_mapping[i] = j;
545         break;
546       }
547     }
548
549     if (j == global_colormap_entries_used)      /* color not found */
550     {
551       if (global_colormap_entries_used < MAX_COLORS)
552         global_colormap_entries_used++;
553
554       global_colormap[j].r = r;
555       global_colormap[j].g = g;
556       global_colormap[j].b = b;
557
558       pixel_mapping[i] = j;
559     }
560 #else
561     pixel_mapping[i] = AllocColorCell(image->rgb.red[i],
562                                       image->rgb.green[i],
563                                       image->rgb.blue[i]);
564 #endif
565
566   }
567
568   /* copy bitmap data */
569   for (y=0; y<image->height; y++)
570     for (x=0; x<image->width; x++)
571       putpixel(bitmap, x, y, pixel_mapping[*src_ptr++]);
572
573   return bitmap;
574 }
575
576 static BITMAP *Read_PCX_to_AllegroBitmap(char *filename)
577 {
578   BITMAP *bitmap;
579   Image *image;
580
581   /* read the graphic file in PCX format to internal image structure */
582   if ((image = Read_PCX_to_Image(filename)) == NULL)
583     return NULL;
584
585   /* convert internal image structure to allegro bitmap structure */
586   if ((bitmap = Image_to_AllegroBitmap(image)) == NULL)
587     return NULL;
588
589   set_palette(global_colormap);
590
591   return bitmap;
592 }
593
594 int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
595                        Pixmap *pixmap, Pixmap *pixmap_mask)
596 {
597   BITMAP *bitmap;
598
599   if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
600     return errno_pcx;
601
602   *pixmap = (Pixmap)bitmap;
603   *pixmap_mask = (Pixmap)bitmap;
604
605   return PCX_Success;
606 }
607
608 int XReadBitmapFile(Display *display, Drawable d, char *filename,
609                     unsigned int *width_return, unsigned int *height_return,
610                     Pixmap *bitmap_return,
611                     int *x_hot_return, int *y_hot_return)
612 {
613   BITMAP *bitmap;
614
615   if ((bitmap = Read_PCX_to_AllegroBitmap(filename)) == NULL)
616     return BitmapOpenFailed;
617
618   *width_return = bitmap->w;
619   *height_return = bitmap->h;
620   *x_hot_return = -1;
621   *y_hot_return = -1;
622   *bitmap_return = (Pixmap)bitmap;
623
624   return BitmapSuccess;
625 }
626
627 void XFreePixmap(Display *display, Pixmap pixmap)
628 {
629   if (pixmap != DUMMY_MASK &&
630       (is_memory_bitmap((BITMAP *)pixmap) ||
631        is_screen_bitmap((BITMAP *)pixmap)))
632     destroy_bitmap((BITMAP *)pixmap);
633 }
634
635 void XFreeGC(Display *display, GC gc)
636 {
637   XGCValues *gcv;
638
639   gcv = (XGCValues *)gc;
640   if (gcv)
641     free(gcv);
642 }
643
644 void XCloseDisplay(Display *display)
645 {
646   BITMAP *bitmap = video_bitmap;
647
648   if (is_screen_bitmap(bitmap))
649     destroy_bitmap(bitmap);
650
651   if (display->screens)
652     free(display->screens);
653
654   if (display)
655     free(display);
656
657   /* return to text mode (or DOS box on Windows screen) */
658   set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
659 }
660
661 void XNextEvent(Display *display, XEvent *event_return)
662 {
663   while (!pending_events)
664     XPending(display);
665
666   memcpy(event_return, &event_buffer[pending_events], sizeof(XEvent));
667   pending_events--;
668 }
669
670 static void NewKeyEvent(int key_press_state, KeySym keysym)
671 {
672   XKeyEvent *xkey;
673
674   if (pending_events >= MAX_EVENT_BUFFER)
675     return;
676
677   pending_events++;
678   xkey = (XKeyEvent *)&event_buffer[pending_events];
679   xkey->type = key_press_state;
680   xkey->state = (unsigned int)keysym;
681 }
682
683 #define HANDLE_RAW_KB_ALL_KEYS                  0
684 #define HANDLE_RAW_KB_MODIFIER_KEYS_ONLY        1
685
686 static int modifier_scancode[] =
687 {
688   KEY_LSHIFT,
689   KEY_RSHIFT,
690   KEY_LCONTROL,
691   KEY_RCONTROL,
692   KEY_ALT,
693   KEY_ALTGR,
694   KEY_LWIN,
695   KEY_RWIN,
696   KEY_CAPSLOCK,
697   KEY_NUMLOCK,
698   KEY_SCRLOCK,
699   -1
700 };
701
702 static void HandleKeyboardRaw(int mode)
703 {
704   int i;
705
706   for (i=0; i<MAX_SCANCODES; i++)
707   {
708     int scancode, new_state, event_type;
709     char key_pressed;
710
711     if (mode == HANDLE_RAW_KB_MODIFIER_KEYS_ONLY)
712     {
713       if ((scancode = modifier_scancode[i]) == -1)
714         return;
715     }
716     else
717       scancode = i;
718
719     key_pressed = key[scancode];
720     new_state = (key_pressed ? KeyPressMask : KeyReleaseMask);
721     event_type = (key_pressed ? KeyPress : KeyRelease);
722
723     if (key_press_state[i] == new_state)        /* state not changed */
724       continue;
725
726     key_press_state[i] = new_state;
727
728     NewKeyEvent(event_type, ScancodeToKeySym(scancode));
729   }
730 }
731
732 static void HandleKeyboardEvent()
733 {
734   if (keypressed())
735   {
736     int key_info = readkey();
737     int scancode = (key_info >> 8);
738     int ascii = (key_info & 0xff);
739     KeySym keysym = ScancodeToKeySym(scancode);
740
741     if (scancode == KEY_PAD)
742     {
743       /* keys on the numeric keypad return just scancode 'KEY_PAD'
744          for some reason, so we must handle them separately */
745
746       if (ascii >= '0' && ascii <= '9')
747         keysym = XK_KP_0 + (KeySym)(ascii - '0');
748       else if (ascii == '.')
749         keysym = XK_KP_Separator;
750     }
751     else if (ascii >= ' ' && ascii <= 'Z')
752       keysym = XK_space + (KeySym)(ascii - ' ');
753     else if (ascii == '^')
754       keysym = XK_asciicircum;
755     else if (ascii == '_')
756       keysym = XK_underscore;
757     else if (ascii == 'Ä')
758       keysym = XK_Adiaeresis;
759     else if (ascii == 'Ö')
760       keysym = XK_Odiaeresis;
761     else if (ascii == 'Ü')
762       keysym = XK_Udiaeresis;
763     else if (ascii == 'ä')
764       keysym = XK_adiaeresis;
765     else if (ascii == 'ö')
766       keysym = XK_odiaeresis;
767     else if (ascii == 'ü')
768       keysym = XK_udiaeresis;
769     else if (ascii == 'ß')
770       keysym = XK_ssharp;
771
772     NewKeyEvent(KeyPress, keysym);
773   }
774   else if (key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG | KB_ALT_FLAG))
775   {
776     /* the allegro function keypressed() does not give us single pressed
777        modifier keys, so we must detect them with the internal global
778        allegro variable 'key_shifts' and then handle them separately */
779
780     HandleKeyboardRaw(HANDLE_RAW_KB_MODIFIER_KEYS_ONLY);
781   }
782 }
783
784 int XPending(Display *display)
785 {
786   XButtonEvent *xbutton;
787   XMotionEvent *xmotion;
788   int i;
789
790   /* When using 'HandleKeyboardRaw()', keyboard input is also stored in
791      the allegro keyboard input buffer and would be available a second
792      time by calling 'HandleKeyboardEvent()'. To avoid double keyboard
793      events, the allegro function 'clear_keybuf()' must be called each
794      time when switching from calling 'HandleKeyboardRaw()' to calling
795      'HandleKeyboardEvent()' to get keyboard input, which is actually
796      done by 'XAutoRepeatOn()' which sets keyboard_auto_repeat to TRUE. */
797
798   /* keyboard event */
799   if (keyboard_auto_repeat)
800     HandleKeyboardEvent();
801   else
802     HandleKeyboardRaw(HANDLE_RAW_KB_ALL_KEYS);
803
804   /* mouse motion event */
805   if (mouse_pos != last_mouse_pos)
806   {
807     last_mouse_pos = mouse_pos;
808     pending_events++;
809     xmotion = (XMotionEvent *)&event_buffer[pending_events];
810     xmotion->type = MotionNotify;
811     xmotion->x = mouse_x - AllegroDefaultScreen().x;
812     xmotion->y = mouse_y - AllegroDefaultScreen().y;
813   }
814
815   /* mouse button event */
816   if (mouse_b != last_mouse_b)
817   {
818     for (i=0; i<3; i++)         /* check all three mouse buttons */
819     {
820       int bitmask = (1 << i);
821
822       if ((last_mouse_b & bitmask) != (mouse_b & bitmask))
823       {
824         int mapping[3] = { 1, 3, 2 };
825
826         pending_events++;
827         xbutton = (XButtonEvent *)&event_buffer[pending_events];
828         xbutton->type = (mouse_b & bitmask ? ButtonPress : ButtonRelease);
829         xbutton->button = mapping[i];
830         xbutton->x = mouse_x - AllegroDefaultScreen().x;
831         xbutton->y = mouse_y - AllegroDefaultScreen().y;
832       }
833     }
834     last_mouse_b = mouse_b;
835   }
836
837   return pending_events;
838 }
839
840 KeySym XLookupKeysym(XKeyEvent *key_event, int index)
841 {
842   return key_event->state;
843 }
844
845 int XLookupString(XKeyEvent *key_event, char *buffer, int buffer_size,
846                   KeySym *key, XComposeStatus *compose)
847 {
848   *key = key_event->state;
849   return 0;
850 }
851
852 void XSetForeground(Display *display, GC gc, unsigned long pixel)
853 {
854   XGCValues *gcv = (XGCValues *)gc;
855
856   gcv->foreground = pixel;
857 }
858
859 void XDrawLine(Display *display, Drawable d, GC gc,
860                int x1, int y1, int x2, int y2)
861 {
862   XGCValues *gcv = (XGCValues *)gc;
863   boolean mouse_off = FALSE;
864
865   if ((BITMAP *)d == video_bitmap)
866   {
867     x1 += AllegroDefaultScreen().x;
868     y1 += AllegroDefaultScreen().y;
869     x2 += AllegroDefaultScreen().x;
870     y2 += AllegroDefaultScreen().y;
871     freeze_mouse_flag = TRUE;
872     mouse_off = hide_mouse(display, MIN(x1, x2), MIN(y1, y2),
873                            MAX(x1, x2) - MIN(x1, x2),
874                            MAX(y1, y2) - MIN(y1, y2));
875   }
876
877   line((BITMAP *)d, x1, y1, x2, y2, gcv->foreground);
878
879   if (mouse_off)
880     unhide_mouse(display);
881
882   freeze_mouse_flag = FALSE;
883 }
884
885 void XDestroyImage(XImage *ximage)
886 {
887 }
888
889 Bool XQueryPointer(Display *display, Window window,
890                    Window *root, Window *child, int *root_x, int *root_y,
891                    int *win_x, int *win_y, unsigned int *mask)
892 {
893   *win_x = mouse_x - AllegroDefaultScreen().x;
894   *win_y = mouse_y - AllegroDefaultScreen().y;
895
896   return True;
897 }
898
899 void XAutoRepeatOn(Display *display)
900 {
901   keyboard_auto_repeat = TRUE;
902   clear_keybuf();
903 }
904
905 void XAutoRepeatOff(Display *display)
906 {
907   keyboard_auto_repeat = FALSE;
908 }
909
910 boolean MSDOSOpenAudio(void)
911 {
912   return allegro_init_audio();
913 }
914
915 void MSDOSCloseAudio(void)
916 {
917   /* nothing to be done here */
918 }
919
920 void NetworkServer(int port, int serveronly)
921 {
922   Error(ERR_WARN, "networking not supported in DOS version");
923 }
924
925 #endif /* PLATFORM_MSDOS */