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