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