--- Xvisual.h.orig	Sun Mar 15 09:33:49 1998
+++ Xvisual.h	Mon Apr 27 05:02:01 1998
@@ -23,6 +23,9 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/keysym.h>
+#ifdef XF86MISC
+#  include <X11/extensions/xf86misc.h>
+#endif
 
 #if defined(__CYGWIN32__) || defined (_AIX)
 #define NO_SHM
@@ -77,6 +80,20 @@
 	sint16 oldmousex;
 	sint16 oldmousey;
 	uint8 relptr_keymask;
+
+		/* default kbd rates: */
+	int  initial_key_delay;
+	int  key_delay;
+
+	struct timeval last_tv;
+	int  last_time;
+	char last_code;
+	int  last_repeating;
+	int  last_sym;
+		/* To get kbd repeat rate settings: */
+#ifdef XF86MISC
+	XF86MiscKbdSettings kbdinfo;
+#endif
 };
 
 #define XLIB_PRIV(vis) ((struct Xhooks *)VIS_PRIVATE(vis))
--- events.c.orig	Tue Mar 10 09:33:54 1998
+++ events.c	Mon Apr 27 05:02:01 1998
@@ -40,9 +40,10 @@
 
 #include <X11/cursorfont.h>
 
+
 static uint32 translate_key(KeySym sym)
 {
-	switch(sym) { 
+	switch(sym) {
 		case XK_VoidSymbol: return U(K_VOID);
 		case XK_BackSpace : return U(8);
 		case XK_Tab       : return U(9);
@@ -663,12 +664,12 @@
 			    struct timeval *t)
 {
 #define BUFFER_SIZE (sizeof(ggi_event)*4)
-	
-	
+
+
 #define XlibWaitLock	while(xhook->XLibLock++!=0) \
 	{xhook->XLibLock--;usleep(1000);}     /* FIXME use spinlocks here !*/
 #define	XlibReleaseLock	xhook->XLibLock--
-	
+
 	KeySym relsyms[RELPTR_NUMKEYS] = RELPTR_KEYS;
 	fd_set fds;
 	int err,n;
@@ -684,8 +685,50 @@
 	DPRINT(",{%d,%d})\n",t->tv_sec,t->tv_usec);
 }
 
+				/* WHS: autorepeat stuff */
+			if (xhook->last_sym) {
+				long sec_diff, usec_diff, total_diff;
+
+				gettimeofday(&tod,NULL);
+				sec_diff = tod.tv_sec-xhook->last_tv.tv_sec;
+				usec_diff = tod.tv_usec-xhook->last_tv.tv_usec;
+				total_diff = (sec_diff-1)*1000+((usec_diff+1000000)/1000); /*approx milliseconds */
+
+				ggievent.any.type=evKeyRepeat;
+				ggievent.key.sym=xhook->last_sym;
+				ggievent.key.code=xhook->last_code;
+
+				ggievent.any.size=sizeof(ggi_key_event);
+				ggievent.key.effect=0;
+				ggievent.key.normal=0;
+				ggievent.key.locked=0;
+				ggievent.key.sticky=0;
+
+				while (total_diff>xhook->key_delay) { /* assume initial_key_delay>key_delay */
+					if (!xhook->last_repeating) {
+						if (total_diff>xhook->initial_key_delay) {	/* First repeat */
+							xhook->last_repeating=1;
+							_ggiEvQueueAdd(vis,&ggievent);
+							xhook->last_tv.tv_usec +=xhook->initial_key_delay*1000;
+							if (xhook->last_tv.tv_usec >1000000) { xhook->last_tv.tv_usec -=1000000; xhook->last_tv.tv_sec++; }
+							total_diff -=xhook->initial_key_delay;
+						}
+						else { /* Not time yet for first repeat */
+							break;
+						}
+					}
+					else { /* 2+ repeat */
+						_ggiEvQueueAdd(vis,&ggievent);
+						xhook->last_tv.tv_usec +=xhook->key_delay*1000;
+						if (xhook->last_tv.tv_usec >1000000) { xhook->last_tv.tv_usec -=1000000; xhook->last_tv.tv_sec++; }
+						total_diff -=xhook->key_delay;
+					}
+				}
+			}
+
+
 	evmask=_ggiEvQueueSeen(vis,mask);
-	if (evmask!=0)  
+	if (evmask!=0)
 		return evmask;
 
 	gettimeofday(&tod,NULL);
@@ -742,7 +785,7 @@
 			ggievent.any.time=0;	/* FIXME ! */
 			ggievent.any.type=0;
 
-			switch(event.type) { 
+			switch(event.type) {
 				case KeyPress:
 				{
 					int i;
@@ -795,6 +838,20 @@
 					ggievent.key.sym=translate_key(sym);
 					XlibReleaseLock;
 					ggievent.key.code=event.xkey.keycode;
+
+						/* WHS: autorepeat */
+					if (event.xkey.time>xhook->last_time) { /* New key press, is it a repeat-allowed one? */
+						if (sym<256 || sym==XK_Tab || sym==XK_Delete) { /* or allow repeats for verything but Ctrl,Shift, Alt? */
+							xhook->last_sym=sym;
+							xhook->last_code=event.xkey.keycode;
+							xhook->last_time=event.xkey.time;
+							xhook->last_tv.tv_sec=tod.tv_sec;
+							xhook->last_tv.tv_usec=tod.tv_usec;
+							xhook->last_repeating=0;
+						}
+						else xhook->last_sym=0;
+					}
+
 					break;
 				}
 				case KeyRelease: 
@@ -812,7 +869,14 @@
 					ggievent.key.sym=translate_key(sym);
 					XlibReleaseLock;
 					ggievent.key.code=event.xkey.keycode;
-					DPRINT("KeyRelease.\n"); break;
+
+					if (xhook->last_sym==sym) {
+						xhook->last_sym=0;
+						xhook->last_repeating=0;
+					}
+					DPRINT("KeyRelease.\n");
+					break;
+
 				}
 				case ButtonPress:
 					ggievent.any.type=evPtrButtonPress;
@@ -868,9 +932,25 @@
 					DPRINT("MouseMove %d,%d.\n",
 						   event.xmotion.x,event.xmotion.y); 
 					break;
+
+			case EnterNotify:
+					/* Adjust settings (may have changed while we were away) */
+#ifdef XF86MISC
+				XF86MiscGetKbdSettings(xhook->display, &kbdinfo);
+				initial_key_delay = kbdinfo.delay;
+				key_delay = 1000/kbdinfo.rate;
+#endif
+				XAutoRepeatOff(xhook->display);
+				xhook->last_sym=0;
+				break;
+			case LeaveNotify:
+				XAutoRepeatOn(xhook->display);
+				xhook->last_sym=0;
+			break;
+
 				default: 
 					DPRINT("Other Event (%d).\n",event.type); break;
-			}      
+			}
 			switch(ggievent.any.type) {
 				case evKeyPress:
 				case evKeyRelease:
--- mode.c.orig	Thu Apr 23 20:24:27 1998
+++ mode.c	Mon Apr 27 05:24:45 1998
@@ -39,6 +39,7 @@
 #include "Xvisual.h"
 #include "../common/X-mode.inc"
 
+
 int GGIsetorigin(ggi_visual *vis,int x,int y)
 {
 	struct Xhooks *xhook=VIS_PRIVATE(vis);
@@ -199,6 +200,28 @@
 				  xhook->visheight-xhook->ysplit);
 	}
 
+		/* autorepeat stuff */
+		/* restore kbd even when not listening to ggi events */
+	{
+		XEvent xevent;
+		while (XCheckMaskEvent(xhook->display, EnterWindowMask | LeaveWindowMask, &xevent)) {
+			switch (xevent.xany.type) {
+			case EnterNotify:
+					/* Adjust settings (may have changed while we were away) */
+#ifdef XF86MISC
+				XF86MiscGetKbdSettings(xhook->display, &xhook->kbdinfo);
+				xhook->initial_key_delay = kbdinfo.delay;
+				xhook->key_delay = 1000/kbdinfo.rate;
+#endif
+				XAutoRepeatOff(xhook->display);
+				xhook->last_sym=0;
+				break;
+			}
+		}
+	}
+ 
+
+
 	XSync(xhook->display,0);
 	xhook->XLibLock--;	/* FIXME Spinlocks ... */
 
@@ -294,6 +317,7 @@
 	XSelectInput(xhook->display, xhook->window,
 	             KeyPressMask|KeyReleaseMask|
 	             ButtonPressMask|ButtonReleaseMask|
+				 EnterWindowMask | LeaveWindowMask |
 	             PointerMotionMask);
 
 	/* Tell other applications about this window */
@@ -398,6 +422,7 @@
 	XSelectInput(xhook->display, xhook->window, 
 				 KeyPressMask|KeyReleaseMask|
 				 ButtonPressMask|ButtonReleaseMask|
+				 EnterWindowMask | LeaveWindowMask |
 				 PointerMotionMask);
 
 	if (xhook->cmap)
@@ -407,10 +432,10 @@
 		xhook->cmap = XCreateColormap(xhook->display, xhook->window, 
 									  vinfo.visual, 
 									  AllocAll);
-		 
+
 		xhook->cmap_first=256;
 		xhook->cmap_last=0;
-		 
+
 		DPRINT("X-lib colormap allocated %x.\n",xhook->cmap);
 	} else {
 		xhook->cmap = XCreateColormap(xhook->display, xhook->window, 
--- visual.c.orig	Fri Apr 24 02:02:22 1998
+++ visual.c	Mon Apr 27 05:19:27 1998
@@ -66,8 +66,14 @@
 	xinfo->isasync=1;  /* Yes, this SHOULD be initialized to 1. */
 	xinfo->relptr=0;
 	xinfo->relptr_keymask = RELPTR_KEYINUSE;
-	xinfo->colormap=NULL;
-	
+
+		/* autorepeat stuff */
+	xinfo->initial_key_delay = 500; /* delay until the first repeat of a key */
+	xinfo->key_delay = 50;
+	xinfo->last_repeating=0;
+	xinfo->last_sym=0;
+
+	xinfo->colormap=NULL;	
 //printf("colormap set to NULL\n");
 	/* We do not use the XLibLock here, as there is no concurrent thread yet. */
 	
@@ -78,6 +84,9 @@
 
 	DPRINT("X-lib has display %s.\n",args);
 
+		/* autorepeat stuff */
+	XAutoRepeatOff(xinfo->display);
+
 #ifndef NO_SHM
 	if (XShmQueryExtension(xinfo->display)) {
 		
@@ -114,7 +123,7 @@
 	struct Xhooks *xinfo;
 
     ggiFlush(vis);
-    
+
 	/* prevents a soon-to-be unloaded function from being called */
 	if (!(VIS_FLAGS(vis) & GGIFLAG_ASYNC))
 		_mansync_stop(vis);
@@ -138,8 +147,10 @@
 			XFreeGC(xinfo->display,xinfo->gc);
         if (xinfo->window)
 			XDestroyWindow(xinfo->display,xinfo->window);
-		if (xinfo->display)
+		if (xinfo->display) {
+			XAutoRepeatOn(xinfo->display); /* always on, other behaviour (getting the settings on enter/leave notify) isn't really dependable as programs running in the bg might quit and mess things up while this app has control */
 			XCloseDisplay(xinfo->display);
+		}
 		free(VIS_PRIVATE(vis));
 	}
 
