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