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