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