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