/*
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
COPYRIGHT 1993-1999 PARALLAX SOFTWARE EVE.  ALL RIGHTS RESERVED.
*/

#ifdef HAVE_CONFIG_H
#include <conf.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

#include "descent.h"
#include "error.h"
#include "key.h"
#include "gamefont.h"
#include "iff.h"
#include "u_mem.h"
#include "joy.h"
#include "mouse.h"
#include "kconfig.h"
#include "cockpit.h"
#include "rendermine.h"
#include "endlevel.h"
#include "timer.h"
#include "text.h"
#include "automap.h"
#include "args.h"
#include "input.h"
#include "menu.h"
#include "strutil.h"
#include "collide.h"
#include "menubackground.h"
#include "songs.h"
#include "headlight.h"
#include "ogl_render.h"
#include "renderframe.h"
#if defined (TACTILE)
#	include "tactile.h"
#endif
#ifdef USE_LINUX_JOY
#	include "joystick.h"
#endif

//added/removed by Victor Rachels for adding rebindable keys for these
// KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0
ubyte system_keys [] = { (ubyte) KEY_ESC, (ubyte) KEY_F1, (ubyte) KEY_F2, (ubyte) KEY_F3, (ubyte) KEY_F4, (ubyte) KEY_F5, (ubyte) KEY_F6, (ubyte) KEY_F7, (ubyte) KEY_F8, (ubyte) KEY_F9, (ubyte) KEY_F10, (ubyte) KEY_F11, (ubyte) KEY_F12, (ubyte) KEY_MINUS, (ubyte) KEY_EQUALS, (ubyte) KEY_ALTED+KEY_F9 };

#define TABLE_CREATION 0

// Array used to 'blink' the cursor while waiting for a keypress.
sbyte fades [64] = { 1,1,1,2,2,3,4,4,5,6,8,9,10,12,13,15,16,17,19,20,22,23,24,26,27,28,28,29,30,30,31,31,31,31,31,30,30,29,28,28,27,26,24,23,22,20,19,17,16,15,13,12,10,9,8,6,5,4,4,3,2,2,1,1 };

//char * yesNoTextIndex [2] = { "N", "Y" };
//char * joybutton_text [28] = { "TRIG", "BTN 1", "BTN 2", "BTN 3", "BTN 4", "", "LEFT", "HAT ", "RIGHT", "", "", "HAT ", "MID", "", "", "HAT ", "", "", "", "HAT ", "TRIG", "LEFT", "RIGHT", "", "UP","DOWN","LEFT", "RIGHT" };
//char * JOYAXIS_TEXT [4] = { "X1", "Y1", "X2", "Y2" };
//char * mouseAxisTextIndex [2] = { "L/R", "F/B" };
//char * mouseButtonTextIndex [3] = { "Left", "Right", "Mid" };

int yesNoTextIndex [2] = { TNUM_N, TNUM_Y };

#ifndef USE_LINUX_JOY
	int joybutton_text [28] =
 { TNUM_BTN_1, TNUM_BTN_2, TNUM_BTN_3, TNUM_BTN_4,
	  -1, TNUM_TRIG, TNUM_LEFT, TNUM_HAT_L,
	 TNUM_RIGHT, -1, TNUM_HAT2_D, TNUM_HAT_R,
	 TNUM_MID, -1, TNUM_HAT2_R, TNUM_HAT_U,
	 TNUM_HAT2_L, -1, TNUM_HAT2_U, TNUM_HAT_D,
	 TNUM_TRIG, TNUM_LEFT, TNUM_RIGHT, -1,
	 TNUM_UP, TNUM_DOWN, TNUM_LEFT, TNUM_RIGHT };

	int joyaxis_text [7] = { TNUM_X1, TNUM_Y1, TNUM_Z1, TNUM_R1, TNUM_P1,TNUM_R1,TNUM_YA1 };
//	int JOYAXIS_TEXT [4] = { TNUM_X1, TNUM_Y1, TNUM_X2, TNUM_Y2 };
#endif

#if 0
#	define JOYAXIS_TEXT(v)		joyaxis_text [ (v) % MAX_AXES_PER_JOYSTICK]
#	define JOYBUTTON_TEXT(v)	joybutton_text [ (v) % MAX_BUTTONS_PER_JOYSTICK]
#endif

int mouseAxisTextIndex [3] = {TNUM_L_R, TNUM_F_B, TNUM_Z1};
int mouseButtonTextIndex [3] = {TNUM_LEFT, TNUM_RIGHT, TNUM_MID};
const char * extraMouseButtonTextIndex [13] = { "MW UP", "MW DN", "M6", "M7", "M8", "M9", "M10","M11","M12","M13","M14","M15","M16" };//text for buttons above 3. -MPM

#define LHX(x)      (gameStates.menus.bHires?2* (x):x)
#define LHY(y)      (gameStates.menus.bHires? (24* (y))/10:y)

const char *btype_text [] = { "BT_KEY", "BT_MOUSE_BUTTON", "BT_MOUSE_AXIS", "BT_JOY_BUTTON", "BT_JOY_AXIS", "BT_INVERT" };

#define INFO_Y 28

int m_nItems=28;
kcItem *m_items;

//----------- WARNING!!!!!!! -------------------------------------------
// THESE NEXT FOUR BLOCKS OF DATA ARE GENERATED BY PRESSING DEL+F12 WHEN
// IN THE KEYBOARD CONFIG SCREEN.  BASICALLY, THAT PROCEDURE MODIFIES THE
// U,D,L,R FIELDS OF THE ARRAYS AND DUMPS THE NEW ARRAYS INTO KCONFIG.COD
//-------------------------------------------------------------------------

tControlSettings controlSettings = {
 {
 {0xc8,0x48,0xd0,0x50,0xcb,0x4b,0xcd,0x4d,0x38,0xff,0xff,0x4f,0xff,0x51,0xff,0x4a,0xff,0x4e,0xff,0xff,0x10,0x47,0x12,0x49,0x1d,0x9d,0x39,0xff,0x21,0xff,0x1e,0xff,0x2c,0xff,0x30,0xff,0x13,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf,0xff,0x1f,0xff,0x33,0xff,0x34,0xff,0x23,0xff,0x14,0xff,0xff,0xff,0x0,0x0},
 {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0},
 {0x5,0xc,0xff,0xff,0xff,0xff,0x7,0xf,0x13,0xb,0xff,0x6,0x8,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0},
 {0x0,0x1,0xff,0xff,0x2,0xff,0x7,0xf,0x13,0xb,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x3,0x0,0x1,0x2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x0,0x1,0xff,0xff,0x2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0},
	},
 {
 {0xc8,0x48,0xd0,0x50,0xcb,0x4b,0xcd,0x4d,0x38,0xff,0xff,0x4f,0xff,0x51,0xff,0x4a,0xff,0x4e,0xff,0xff,0x10,0x47,0x12,0x49,0x1d,0x9d,0x39,0xff,0x21,0xff,0x1e,0xff,0x2c,0xff,0x30,0xff,0x13,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf,0xff,0x1f,0xff,0x33,0xff,0x34,0xff,0x23,0xff,0x14,0xff,0xff,0xff,0x0,0x0},
 {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0},
 {0x5,0xc,0xff,0xff,0xff,0xff,0x7,0xf,0x13,0xb,0xff,0x6,0x8,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0},
 {0x0,0x1,0xff,0xff,0x2,0xff,0x7,0xf,0x13,0xb,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x3,0x0,0x1,0x2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x0,0x1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1,0x0,0x0,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0},
 {0x0,0x1,0xff,0xff,0x2,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0x0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0},
	},
 {
	0x2 ,0xff,0x3 ,0xff,0x4 ,0xff,0x5 ,0xff,0x6 ,0xff,0x7 ,0xff,0x8 ,0xff,0x9 ,
	0xff,0xa ,0xff,0xb ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
	},
 {
	0x2 ,0xff,0x3 ,0xff,0x4 ,0xff,0x5 ,0xff,0x6 ,0xff,0x7 ,0xff,0x8 ,0xff,0x9 ,
	0xff,0xa ,0xff,0xb ,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
	}
};

kcItem kcKeyboard [] = {
 {  0, 15, 49, 71, 26, 62, 2, 63, 1,"Pitch forward", 270, BT_KEY, 255 },
 {  1, 15, 49,100, 26, 63, 3, 0, 24,"Pitch forward", 270, BT_KEY, 255 },
 {  2, 15, 57, 71, 26, 0, 4, 25, 3,"Pitch backward", 271, BT_KEY, 255 },
 {  3, 15, 57,100, 26, 1, 5, 2, 26,"Pitch backward", 271, BT_KEY, 255 },
 {  4, 15, 65, 71, 26, 2, 6, 27, 5,"Turn left", 272, BT_KEY, 255 },
 {  5, 15, 65,100, 26, 3, 7, 4, 28,"Turn left", 272, BT_KEY, 255 },
 {  6, 15, 73, 71, 26, 4, 8, 29, 7,"Turn right", 273, BT_KEY, 255 },
 {  7, 15, 73,100, 26, 5, 9, 6, 34,"Turn right", 273, BT_KEY, 255 },
 {  8, 15, 84, 71, 26, 6, 10, 35, 9,"Slide on", 274, BT_KEY, 255 },
 {  9, 15, 84,100, 26, 7, 11, 8, 36,"Slide on", 274, BT_KEY, 255 },
 { 10, 15, 92, 71, 26, 8, 12, 37, 11,"Slide left", 275, BT_KEY, 255 },
 { 11, 15, 92,100, 26, 9, 13, 10, 44,"Slide left", 275, BT_KEY, 255 },
 { 12, 15,100, 71, 26, 10, 14, 45, 13,"Slide right", 276, BT_KEY, 255 },
 { 13, 15,100,100, 26, 11, 15, 12, 30,"Slide right", 276, BT_KEY, 255 },
 { 14, 15,108, 71, 26, 12, 16, 31, 15,"Slide up", 277, BT_KEY, 255 },
 { 15, 15,108,100, 26, 13, 17, 14, 32,"Slide up", 277, BT_KEY, 255 },
 { 16, 15,116, 71, 26, 14, 18, 33, 17,"Slide down", 278, BT_KEY, 255 },
 { 17, 15,116,100, 26, 15, 19, 16, 46,"Slide down", 278, BT_KEY, 255 },
 { 18, 15,127, 71, 26, 16, 20, 47, 19,"Bank on", 279, BT_KEY, 255 },
 { 19, 15,127,100, 26, 17, 21, 18, 38,"Bank on", 279, BT_KEY, 255 },
 { 20, 15,135, 71, 26, 18, 22, 39, 21,"Bank left", 280, BT_KEY, 255 },
 { 21, 15,135,100, 26, 19, 23, 20, 40,"Bank left", 280, BT_KEY, 255 },
 { 22, 15,143, 71, 26, 20, 48, 41, 23,"Bank right", 281, BT_KEY, 255 },
 { 23, 15,143,100, 26, 21, 49, 22, 42,"Bank right", 281, BT_KEY, 255 },
 { 24,158, 49, 83, 26, 59, 26, 1, 25,"Fire primary", 282, BT_KEY, 255 },
 { 25,158, 49,112, 26, 57, 27, 24, 2,"Fire primary", 282, BT_KEY, 255 },
 { 26,158, 57, 83, 26, 24, 28, 3, 27,"Fire secondary", 283,BT_KEY, 255 },
 { 27,158, 57,112, 26, 25, 29, 26, 4,"Fire secondary", 283,BT_KEY, 255 },
 { 28,158, 65, 83, 26, 26, 34, 5, 29,"Fire flare", 284,BT_KEY, 255 },
 { 29,158, 65,112, 26, 27, 35, 28, 6,"Fire flare", 284,BT_KEY, 255 },
 { 30,158,103, 83, 26, 44, 32, 13, 31,"Accelerate", 285,BT_KEY, 255 },
 { 31,158,103,112, 26, 45, 33, 30, 14,"Accelerate", 285,BT_KEY, 255 },
 { 32,158,111, 83, 26, 30, 46, 15, 33,"reverse", 286,BT_KEY, 255 },
 { 33,158,111,112, 26, 31, 47, 32, 16,"reverse", 286,BT_KEY, 255 },
 { 34,158, 73, 83, 26, 28, 36, 7, 35,"Drop Bomb", 287,BT_KEY, 255 },
 { 35,158, 73,112, 26, 29, 37, 34, 8,"Drop Bomb", 287,BT_KEY, 255 },
 { 36,158, 84, 83, 26, 34, 44, 9, 37,"Rear View", 288,BT_KEY, 255 },
 { 37,158, 84, 112, 26, 35, 45, 36, 10,"Rear View", 288,BT_KEY, 255 },
 { 38,158,130, 83, 26, 46, 40, 19, 39,"Cruise Faster", 289,BT_KEY, 255 },
 { 39,158,130,112, 26, 47, 41, 38, 20,"Cruise Faster", 289,BT_KEY, 255 },
 { 40,158,138, 83, 26, 38, 42, 21, 41,"Cruise Slower", 290,BT_KEY, 255 },
 { 41,158,138,112, 26, 39, 43, 40, 22,"Cruise Slower", 290,BT_KEY, 255 },
 { 42,158,146, 83, 26, 40, 54, 23, 43,"Cruise Off", 291,BT_KEY, 255 },
 { 43,158,146,112, 26, 41, 55, 42, 48,"Cruise Off", 291,BT_KEY, 255 },
 { 44,158, 92, 83, 26, 36, 30, 11, 45,"Automap", 292,BT_KEY, 255 },
 { 45,158, 92,112, 26, 37, 31, 44, 12,"Automap", 292,BT_KEY, 255 },
 { 46,158,119, 83, 26, 32, 38, 17, 47,"Afterburner", 293,BT_KEY, 255 },
 { 47,158,119,112, 26, 33, 39, 46, 18,"Afterburner", 293,BT_KEY, 255 },
 { 48, 15,154, 71, 26, 22, 50, 43, 49,"Cycle Primary", 294,BT_KEY, 255 },
 { 49, 15,154,100, 26, 23, 51, 48, 54,"Cycle Primary", 294,BT_KEY, 255 },
 { 50, 15,162, 71, 26, 48, 52, 55, 51,"Cycle Second", 295,BT_KEY, 255 },
 { 51, 15,162,100, 26, 49, 53, 50, 56,"Cycle Second", 295,BT_KEY, 255 },
 { 52, 15,170, 71, 26, 50, 60, 57, 53,"Zoom In", 296,BT_KEY, 255 },
 { 53, 15,170,100, 26, 51, 61, 52, 58,"Zoom In", 296,BT_KEY, 255 },
 { 54,158,157, 83, 26, 42, 56, 49, 55,"Headlight", 297,BT_KEY, 255 },
 { 55,158,157,112, 26, 43, 57, 54, 50,"Headlight", 297,BT_KEY, 255 },
 { 56,158,165, 83, 26, 54, 58, 51, 57,"Energy->Shield", 298,BT_KEY, 255 },
 { 57,158,165,112, 26, 55, 25, 56, 52,"Energy->Shield", 298,BT_KEY, 255 },
   { 58,158,173, 83, 26, 56, 59, 53, 60,"Toggle Bomb", 299, BT_KEY,255},
   { 59,158,181, 83, 26, 58, 24, 61, 62,"Toggle Icons", 653, BT_KEY,255},
 { 60, 15,181, 71, 26, 52, 62, 58, 61,"Use Cloak", 751,BT_KEY, 255 },
 { 61, 15,181,100, 26, 53, 63, 60, 59,"Use Cloak", 751,BT_KEY, 255 },
 { 62, 15,189, 71, 26, 60, 0, 59, 63,"Use Invul", 752,BT_KEY, 255 },
 { 63, 15,189,100, 26, 61, 1, 62, 0,"Use Invul", 752,BT_KEY, 255 },
   { 64,158,189, 83, 26, 58, 24, 61, 62,"Slowmo/Speed", 910, BT_KEY,255 },
   { 65,158,189,112, 26, 58, 24, 61, 62,"Slowmo/Speed", 910, BT_KEY,255 }
};

ubyte kcKbdFlags [MAX_CONTROLS];

kcItem kcJoystick [] = {
 {  0, 15, 46, 71, 26, 15, 1, 24, 5,"Fire primary", 282, BT_JOY_BUTTON, 255 },
 {  1, 15, 54, 71, 26, 0, 4, 5, 6,"Fire secondary", 283, BT_JOY_BUTTON, 255 },
 {  2, 15, 94, 71, 26, 35, 3, 10, 11,"Accelerate", 285, BT_JOY_BUTTON, 255 },
 {  3, 15,102, 71, 26, 2, 25, 11, 12,"reverse", 286, BT_JOY_BUTTON, 255 },
 {  4, 15, 62, 71, 26, 1, 26, 6, 7,"Fire flare", 284, BT_JOY_BUTTON, 255 },
 {  5,158, 46, 71, 26, 23, 6, 0, 1,"Slide on", 274, BT_JOY_BUTTON, 255 },
 {  6,158, 54, 71, 26, 5, 7, 1, 4,"Slide left", 275, BT_JOY_BUTTON, 255 },
 {  7,158, 62, 71, 26, 6, 8, 4, 26,"Slide right", 276, BT_JOY_BUTTON, 255 },
 {  8,158, 70, 71, 26, 7, 9, 26, 34,"Slide up", 277, BT_JOY_BUTTON, 255 },
 {  9,158, 78, 71, 26, 8, 10, 34, 35,"Slide down", 278, BT_JOY_BUTTON, 255 },
 { 10,158, 86, 71, 26, 9, 11, 35, 2,"Bank on", 279, BT_JOY_BUTTON, 255 },
 { 11,158, 94, 71, 26, 10, 12, 2, 3,"Bank left", 280, BT_JOY_BUTTON, 255 },
 { 12,158,102, 71, 26, 11, 28, 3, 25,"Bank right", 281, BT_JOY_BUTTON, 255 },
 { 13, 15,162, 51, 26, 33, 15, 32, 14,"Pitch U/D", 300, BT_JOY_AXIS, 255 },
 { 15, 15,170, 51, 26, 13, 0, 18, 16,"Turn L/R", 301, BT_JOY_AXIS, 255 },
 { 17,158,162, 58, 26, 32, 19, 14, 18,"Slide L/R", 302, BT_JOY_AXIS, 255 },
 { 19,158,170, 58, 26, 17, 21, 16, 20,"Slide U/D", 303, BT_JOY_AXIS, 255 },
 { 21,158,178, 58, 26, 19, 23, 20, 22,"Bank L/R", 304, BT_JOY_AXIS, 255 },
 { 23,158,186, 58, 26, 21, 5, 22, 24,"throttle", 305, BT_JOY_AXIS, 255 },
 { 25, 15,110, 71, 26, 3, 27, 12, 28,"Rear View", 288, BT_JOY_BUTTON, 255 },
 { 26, 15, 70, 71, 26, 4, 34, 7, 8,"Drop Bomb", 287, BT_JOY_BUTTON, 255 },
 { 27, 15,118, 71, 26, 25, 30, 28, 29,"Afterburner", 293, BT_JOY_BUTTON, 255 },
 { 28,158,110, 71, 26, 12, 29, 25, 27,"Cycle Primary", 294, BT_JOY_BUTTON, 255 },
 { 29,158,118, 71, 26, 28, 31, 27, 30,"Cycle Secondary", 295, BT_JOY_BUTTON, 255 },
 { 30, 15,126, 71, 26, 27, 33, 29, 31,"Headlight", 297, BT_JOY_BUTTON, 255 },
 { 31,158,126, 71, 26, 29, 32, 30, 33,"Toggle Bomb", 299, BT_JOY_BUTTON, 255 },
 { 32,158,134, 71, 26, 31, 18, 33, 13,"Toggle Icons", 653, BT_JOY_BUTTON, 255 },
 { 33, 15,134, 71, 26, 30, 14, 31, 32,"Automap", 292, BT_JOY_BUTTON, 255 },
 { 34, 15, 78, 71, 26, 26, 35, 8,  9,"Use Cloak", 751, BT_JOY_BUTTON, 255 },
 { 35, 15, 86, 71, 26, 34, 2, 9, 10,"Use Invul", 752, BT_JOY_BUTTON, 255 },

 { 36, 15, 46, 100, 26, 15, 1, 24, 5,"Fire primary", 282, BT_JOY_BUTTON, 255 },
 { 37, 15, 54, 100, 26, 0, 4, 5, 6,"Fire secondary", 283, BT_JOY_BUTTON, 255 },
 { 38, 15, 94, 100, 26, 35, 3, 10, 11,"Accelerate", 285, BT_JOY_BUTTON, 255 },
 { 39, 15,102, 100, 26, 2, 25, 11, 12,"reverse", 286, BT_JOY_BUTTON, 255 },
 { 40, 15, 62, 100, 26, 1, 26, 6, 7,"Fire flare", 284, BT_JOY_BUTTON, 255 },
 { 41,158, 46, 100, 26, 23, 6, 0, 1,"Slide on", 274, BT_JOY_BUTTON, 255 },
 { 42,158, 54, 100, 26, 5, 7, 1, 4,"Slide left", 275, BT_JOY_BUTTON, 255 },
 { 43,158, 62, 100, 26, 6, 8, 4, 26,"Slide right", 276, BT_JOY_BUTTON, 255 },
 { 44,158, 70, 100, 26, 7, 9, 26, 34,"Slide up", 277, BT_JOY_BUTTON, 255 },
 { 45,158, 78, 100, 26, 8, 10, 34, 35,"Slide down", 278, BT_JOY_BUTTON, 255 },
 { 46,158, 86, 100, 26, 9, 11, 35, 2,"Bank on", 279, BT_JOY_BUTTON, 255 },
 { 47,158, 94, 100, 26, 10, 12, 2, 3,"Bank left", 280, BT_JOY_BUTTON, 255 },
 { 48,158,102, 100, 26, 11, 28, 3, 25,"Bank right", 281, BT_JOY_BUTTON, 255 },
 { 49, 15,162, 80, 26, 33, 15, 32, 14,"Pitch U/D", 300, BT_JOY_AXIS, 255 },
 { 50, 15,170, 80, 26, 13, 0, 18, 16,"Turn L/R", 301, BT_JOY_AXIS, 255 },
 { 51,158,162, 87, 26, 32, 19, 14, 18,"Slide L/R", 302, BT_JOY_AXIS, 255 },
 { 52,158,170, 87, 26, 17, 21, 16, 20,"Slide U/D", 303, BT_JOY_AXIS, 255 },
 { 53,158,178, 87, 26, 19, 23, 20, 22,"Bank L/R", 304, BT_JOY_AXIS, 255 },
 { 54,158,186, 87, 26, 21, 5, 22, 24,"throttle", 305, BT_JOY_AXIS, 255 },
 { 55, 15,110, 100, 26, 3, 27, 12, 28,"Rear View", 288, BT_JOY_BUTTON, 255 },
 { 56, 15, 70, 100, 26, 4, 34, 7, 8,"Drop Bomb", 287, BT_JOY_BUTTON, 255 },
 { 57, 15,118, 100, 26, 25, 30, 28, 29,"Afterburner", 293, BT_JOY_BUTTON, 255 },
 { 58,158,110, 100, 26, 12, 29, 25, 27,"Cycle Primary", 294, BT_JOY_BUTTON, 255 },
 { 59,158,118, 100, 26, 28, 31, 27, 30,"Cycle Secondary", 295, BT_JOY_BUTTON, 255 },
 { 60, 15,126, 100, 26, 27, 33, 29, 31,"Headlight", 297, BT_JOY_BUTTON, 255 },
 { 61,158,126, 100, 26, 29, 32, 30, 33,"Toggle Bomb", 299, BT_JOY_BUTTON, 255 },
 { 62,158,134, 100, 26, 31, 18, 33, 13,"Toggle Icons", 653, BT_JOY_BUTTON, 255 },
 { 63, 15,134, 100, 26, 30, 14, 31, 32,"Automap", 292, BT_JOY_BUTTON, 255 },
 { 64, 15, 78, 100, 26, 26, 35, 8,  9,"Use Cloak", 751, BT_JOY_BUTTON, 255 },
 { 65, 15, 86, 100, 26, 34, 2, 9, 10,"Use Invul", 752, BT_JOY_BUTTON, 255 },

 { 14, 15,162,115, 8, 33, 16, 13, 17,"Pitch U/D", 300, BT_INVERT, 255 },
 { 16, 15,170,115, 8, 14, 17, 15, 19,"Turn L/R", 301, BT_INVERT, 255 },
 { 18,158,162,123, 8, 32, 20, 17, 15,"Slide L/R", 302, BT_INVERT, 255 },
 { 20,158,170,123, 8, 18, 22, 19, 21,"Slide U/D", 303, BT_INVERT, 255 },
 { 22,158,178,123, 8, 20, 24, 21, 23,"Bank L/R", 304, BT_INVERT, 255 },
 { 24,158,186,123, 8, 22, 13, 23, 0,"throttle", 305, BT_INVERT, 255 }

};

kcItem kcMouse [] = {
 {  0, 25, 46, 85, 26, 23, 1, 24, 5,"Fire primary", 282, BT_MOUSE_BUTTON, 255 },
 {  1, 25, 54, 85, 26, 0, 4, 5, 6,"Fire secondary", 283, BT_MOUSE_BUTTON, 255 },
 {  2, 25, 78, 85, 26, 26, 3, 8, 9,"Accelerate", 285, BT_MOUSE_BUTTON, 255 },
 {  3, 25, 86, 85, 26, 2, 27, 9, 10,"reverse", 286, BT_MOUSE_BUTTON, 255 },
 {  4, 25, 62, 85, 26, 1, 26, 6, 7,"Fire flare", 284, BT_MOUSE_BUTTON, 255 },
 {  5,180, 46, 59, 26, 24, 6, 0, 1,"Slide on", 274, BT_MOUSE_BUTTON, 255 },
 {  6,180, 54, 59, 26, 5, 7, 1, 4,"Slide left", 275, BT_MOUSE_BUTTON, 255 },
 {  7,180, 62, 59, 26, 6, 8, 4, 26,"Slide right", 276, BT_MOUSE_BUTTON, 255 },
 {  8,180, 70, 59, 26, 7, 9, 26, 2,"Slide up", 277, BT_MOUSE_BUTTON, 255 },
 {  9,180, 78, 59, 26, 8, 10, 2, 3,"Slide down", 278, BT_MOUSE_BUTTON, 255 },
 { 10,180, 86, 59, 26, 9, 11, 3, 27,"Bank on", 279, BT_MOUSE_BUTTON, 255 },
 { 11,180, 94, 59, 26, 10, 12, 27, 25,"Bank left", 280, BT_MOUSE_BUTTON, 255 },
 { 12,180,102, 59, 26, 11, 30, 25, 28,"Bank right", 281, BT_MOUSE_BUTTON, 255 },

 { 13,103,146, 58, 26, 29, 15, 30, 14,"Pitch U/D", 300, BT_MOUSE_AXIS, 255 },
 { 14,103,146,106, 8, 23, 16, 13, 15,"Pitch U/D", 300, BT_INVERT, 255 },
 { 15,103,154, 58, 26, 13, 17, 14, 16,"Turn L/R", 301, BT_MOUSE_AXIS, 255 },
 { 16,103,154,106, 8, 14, 18, 15, 17,"Turn L/R", 301, BT_INVERT, 255 },
 { 17,103,162, 58, 26, 15, 19, 16, 18,"Slide L/R", 302, BT_MOUSE_AXIS, 255 },
 { 18,103,162,106, 8, 16, 20, 17, 19,"Slide L/R", 302, BT_INVERT, 255 },
 { 19,103,170, 58, 26, 17, 21, 18, 20,"Slide U/D", 303, BT_MOUSE_AXIS, 255 },
 { 20,103,170,106, 8, 18, 22, 19, 21,"Slide U/D", 303, BT_INVERT, 255 },
 { 21,103,178, 58, 26, 19, 23, 20, 22,"Bank L/R", 304, BT_MOUSE_AXIS, 255 },
 { 22,103,178,106, 8, 20, 24, 21, 23,"Bank L/R", 304, BT_INVERT, 255 },
 { 23,103,186, 58, 26, 21, 0, 22, 24,"Throttle", 305, BT_MOUSE_AXIS, 255 },
 { 24,103,186,106, 8, 22, 5, 23, 0,"Throttle", 305, BT_INVERT, 255 },

 { 25, 25,102, 85, 26, 27, 28, 11, 12,"Rear View", 288, BT_MOUSE_BUTTON, 255 },
 { 26, 25, 70, 85, 26, 4, 2, 7, 8,"Drop Bomb", 287, BT_MOUSE_BUTTON, 255 },
 { 27, 25, 94, 85, 26, 3, 25, 10, 11,"Afterburner", 293, BT_MOUSE_BUTTON, 255 },
 { 28, 25,110, 85, 26, 25, 29, 12, 29,"Cycle Primary", 294, BT_MOUSE_BUTTON, 255 },
 { 29, 25,118, 85, 26, 28, 13, 28, 30,"Cycle Second", 295, BT_MOUSE_BUTTON, 255 },
 { 30,180,118, 59, 26, 12, 14, 29, 13,"Zoom in", 296, BT_MOUSE_BUTTON, 255 }
};

kcItem kcSuperJoy [] = {
 {  0, 25, 46, 85, 26, 15, 1, 24, 5,"Fire primary", 282, BT_JOY_BUTTON, 255 },
 {  1, 25, 54, 85, 26, 0, 4, 5, 6,"Fire secondary", 283, BT_JOY_BUTTON, 255 },
 {  2, 25, 85, 85, 26, 26, 3, 9, 10,"Accelerate", 285, BT_JOY_BUTTON, 255 },
 {  3, 25, 93, 85, 26, 2, 25, 10, 11,"reverse", 286, BT_JOY_BUTTON, 255 },
 {  4, 25, 62, 85, 26, 1, 26, 6, 7,"Fire flare", 284, BT_JOY_BUTTON, 255 },
 {  5,180, 46, 79, 26, 23, 6, 0, 1,"Slide on", 274, BT_JOY_BUTTON, 255 },
 {  6,180, 54, 79, 26, 5, 7, 1, 4,"Slide left", 275, BT_JOY_BUTTON, 255 },
 {  7,180, 62, 79, 26, 6, 8, 4, 26,"Slide right", 276, BT_JOY_BUTTON, 255 },
 {  8,180, 70, 79, 26, 7, 9, 26, 9,"Slide up", 277, BT_JOY_BUTTON, 255 },
 {  9,180, 78, 79, 26, 8, 10, 8, 2,"Slide down", 278, BT_JOY_BUTTON, 255 },
 { 10,180, 86, 79, 26, 9, 11, 2, 3,"Bank on", 279, BT_JOY_BUTTON, 255 },
 { 11,180, 94, 79, 26, 10, 12, 3, 12,"Bank left", 280, BT_JOY_BUTTON, 255 },
 { 12,180,102, 79, 26, 11, 28, 11, 25,"Bank right", 281, BT_JOY_BUTTON, 255 },
 { 13, 22,162, 51, 26, 33, 15, 32, 14,"Pitch U/D", 300, BT_JOY_AXIS, 255 },
 { 14, 22,162, 99, 8, 33, 16, 13, 17,"Pitch U/D", 300, BT_INVERT, 255 },
 { 15, 22,170, 51, 26, 13, 0, 18, 16,"Turn L/R", 301, BT_JOY_AXIS, 255 },
 { 16, 22,170, 99, 8, 14, 17, 15, 19,"Turn L/R", 301, BT_INVERT, 255 },
 { 17,164,162, 58, 26, 32, 19, 14, 18,"Slide L/R", 302, BT_JOY_AXIS, 255 },
 { 18,164,162,106, 8, 32, 20, 17, 15,"Slide L/R", 302, BT_INVERT, 255 },
 { 19,164,170, 58, 26, 17, 21, 16, 20,"Slide U/D", 303, BT_JOY_AXIS, 255 },
 { 20,164,170,106, 8, 18, 22, 19, 21,"Slide U/D", 303, BT_INVERT, 255 },
 { 21,164,178, 58, 26, 19, 23, 20, 22,"Bank L/R", 304, BT_JOY_AXIS, 255 },
 { 22,164,178,106, 8, 20, 24, 21, 23,"Bank L/R", 304, BT_INVERT, 255 },
 { 23,164,186, 58, 26, 21, 5, 22, 24,"throttle", 305, BT_JOY_AXIS, 255 },
 { 24,164,186,106, 8, 22, 13, 23, 0,"throttle", 305, BT_INVERT, 255 },
 { 25, 25,110, 85, 26, 3, 27, 12, 28,"Rear View", 288, BT_JOY_BUTTON, 255 },
 { 26, 25, 70, 85, 26, 4, 2, 7, 8,"Drop Bomb", 287, BT_JOY_BUTTON, 255 },
 { 27, 25,118, 85, 26, 25, 30, 28, 29,"Afterburner", 293, BT_JOY_BUTTON, 255 },
 { 28,180,110, 79, 26, 12, 29, 25, 27,"Cycle Primary", 294, BT_JOY_BUTTON, 255 },
 { 29,180,118, 79, 26, 28, 31, 27, 30,"Cycle Secondary", 295, BT_JOY_BUTTON, 255 },
 { 30, 25,126, 85, 26, 27, 33, 29, 31,"Headlight", 297, BT_JOY_BUTTON, 255 },
 { 31,180,126, 79, 26, 29, 32, 30, 33,"Toggle Bomb", 299, BT_JOY_BUTTON, 255 },
 { 32,180,134, 79, 26, 31, 18, 33, 13,"Toggle Icons", 653, BT_JOY_BUTTON, 255 },
 { 33, 25,134, 85, 26, 30, 14, 31, 32,"Automap", 292, BT_JOY_BUTTON, 255 },
};

//added on 2/4/99 by Victor Rachels to add d1x new keys
kcItem kcHotkeys [] = {
//        id,x,y,w1,w2,u,d,l,r,text_num1,nType,value
 {  0, 15, 49, 71, 26, 27, 2, 27, 1, "Weapon 1", 306, BT_KEY, 255 },
 {  1, 15, 49,100, 26, 26, 3, 0, 2, "Weapon 1", 306, BT_JOY_BUTTON, 255 },
 {  2, 15, 57, 71, 26, 0, 4, 1, 3, "Weapon 2", 307, BT_KEY, 255 },
 {  3, 15, 57,100, 26, 1, 5, 2, 4, "Weapon 2", 307, BT_JOY_BUTTON, 255 },
 {  4, 15, 65, 71, 26, 2, 6, 3, 5, "Weapon 3", 308, BT_KEY, 255 },
 {  5, 15, 65,100, 26, 3, 7, 4, 6, "Weapon 3", 308, BT_JOY_BUTTON, 255 },
 {  6, 15, 73, 71, 26, 4, 8, 5, 7, "Weapon 4", 309, BT_KEY, 255 },
 {  7, 15, 73,100, 26, 5, 9, 6, 8, "Weapon 4", 309, BT_JOY_BUTTON, 255 },
 {  8, 15, 81, 71, 26, 6, 10, 7, 9, "Weapon 5", 310, BT_KEY, 255 },
 {  9, 15, 81,100, 26, 7, 11, 8, 10, "Weapon 5", 310, BT_JOY_BUTTON, 255 },

 { 10, 15, 89, 71, 26, 8, 12, 9, 11, "Weapon 6", 311, BT_KEY, 255 },
 { 11, 15, 89,100, 26, 9, 13, 10, 12, "Weapon 6", 311, BT_JOY_BUTTON, 255 },
 { 12, 15, 97, 71, 26, 10, 14, 11, 13, "Weapon 7", 312, BT_KEY, 255 },
 { 13, 15, 97,100, 26, 11, 15, 12, 14, "Weapon 7", 312, BT_JOY_BUTTON, 255 },
 { 14, 15,105, 71, 26, 12, 16, 13, 15, "Weapon 8", 313, BT_KEY, 255 },
 { 15, 15,105,100, 26, 13, 17, 14, 16, "Weapon 8", 313, BT_JOY_BUTTON, 255 },
 { 16, 15,113, 71, 26, 14, 18, 15, 17, "Weapon 9", 314, BT_KEY, 255 },
 { 17, 15,113,100, 26, 15, 19, 16, 18, "Weapon 9", 314, BT_JOY_BUTTON, 255 },
 { 18, 15,121, 71, 26, 16, 20, 17, 19, "Weapon 10", 315, BT_KEY, 255 },
 { 19, 15,121,100, 26, 17, 21, 18, 20, "Weapon 10", 315, BT_JOY_BUTTON, 255 }

	//{ 20, 15,131, 71, 26, 18, 22, 19, 21, "CYC PRIMARY", BT_KEY, 255 },
	//{ 21, 15,131,100, 26, 19, 23, 20, 22, "CYC PRIMARY", BT_JOY_BUTTON, 255 },
	//{ 22, 15,139, 71, 26, 20, 24, 21, 23, "CYC SECONDARY", BT_KEY, 255 },
	//{ 23, 15,139,100, 26, 21, 25, 22, 24, "CYC SECONDARY", BT_JOY_BUTTON, 255 },
	//{ 24, 8,147, 78, 26, 22, 26, 23, 25, "TOGGLE_PRIM AUTO", BT_KEY, 255 },
	//{ 25, 8,147,107, 26, 23, 27, 24, 26, "TOGGLE_PRIM_AUTO", BT_JOY_BUTTON, 255 },
	//{ 26, 8,155, 78, 26, 24, 1, 25, 27, "TOGGLE SEC AUTO", BT_KEY, 255 },
	//{ 27, 8,155,107, 26, 25, 0, 26, 0, "TOGGLE SEC AUTO", BT_JOY_BUTTON, 255 },
};
//end this section addition - VR

CExternalControls externalControls;

CFixVector ExtForceVec;
CFixMatrix ExtApplyForceMatrix;

int ExtJoltInfo [3]={0,0,0};
int ExtXVibrateInfo [2]={0,0};
int ExtYVibrateInfo [2]={0,0};
ubyte ExtXVibrateClear=0;
ubyte ExtYVibrateClear=0;

int CControlConfig::m_startAxis [JOY_MAX_AXES];

CControlConfig controlConfig;

//------------------------------------------------------------------------------

int CControlConfig::IsAxisUsed (int axis)
{
for (int i = 0; i < NUM_JOY_CONTROLS; i++) {
	if ((kcJoystick [i].nType == BT_JOY_AXIS) && (kcJoystick [i].value == axis))
		return 1;
	}
return 0;
}

//------------------------------------------------------------------------------

int CControlConfig::FindItemAt (int x, int y)
{
for (int i = 0; i < m_nItems; i++) {
	if (((m_items [i].x + m_items [i].w1) == x) && (m_items [i].y == y))
		return i;
	}
return -1;
}

//------------------------------------------------------------------------------

int CControlConfig::FindNextItemRight (int nItems, int nCurItem, tItemPos *pos, int *ref)
{
nCurItem = ref [nCurItem];
return pos [(nCurItem + 1) % nItems].i;
}

//------------------------------------------------------------------------------

int CControlConfig::FindNextItemLeft (int nItems, int nCurItem, tItemPos *pos, int *ref)
{
nCurItem = ref [nCurItem];
return pos [nCurItem ? nCurItem - 1 : nItems - 1].i;
}

//------------------------------------------------------------------------------

int CControlConfig::FindNextItemUp (int nItems, int nCurItem, tItemPos *pos, int *ref)
{
	int l, r, x, y, yStart, h, i, j, dx, dy, dMin;

h = 0;
i = j = ref [nCurItem];
l = pos [i].l;
r = pos [i].r;
x = (l + r) / 2;
y = yStart = pos [i].y;
#if 0
do {
	if (--i < 0)
		i = m_nItems - 1;
	if ((r >= pos [i].l) && (l <= pos [i].r))
		return pos [i].i;
	} while (i != j);
#endif
dMin = 0x7fffffff;
dy = 0;
for (;;) {
	if (--i < 0)
		i = nItems - 1;
	if (i == j)
		break;
	if (pos [i].y == yStart)
		continue;
	dx = abs (x - (pos [i].l + pos [i].r) / 2);
	if (y != pos [i].y) {
		y = pos [i].y;
		dy += 10;
		}
	dx += dy;
	if (dMin > dx) {
		dMin = dx;
		h = i;
		}
	}
return pos [h].i;
}

//------------------------------------------------------------------------------

int CControlConfig::FindNextItemDown (int nItems, int nCurItem, tItemPos *pos, int *ref)
{
	int l, r, x, y, yStart, h, i, j, dx, dy, dMin;

h = 0;
i = j = ref [nCurItem];
l = pos [i].l;
r = pos [i].r;
x = (l + r) / 2;
y = yStart = pos [i].y;
#if 0
do {
	i = (i + 1) % m_nItems;
	if ((r >= pos [i].l) && (l <= pos [i].r))
		return pos [i].i;
	} while (i != j);
#endif
dMin = 0x7fffffff;
dy = 0;
for (;;) {
	i = (i + 1) % nItems;
	if (i == j)
		break;
	if (pos [i].y == yStart)
		continue;
	dx = abs (x - (pos [i].l + pos [i].r) / 2);
	if (y != pos [i].y) {
		y = pos [i].y;
		dy += 10;
		}
	dx += dy;
	if (dMin > dx) {
		dMin = dx;
		h = i;
		}
	}
return pos [h].i;
}

//------------------------------------------------------------------------------

const char* CControlConfig::MouseButtonText (int i)
{
if (i < 0)
	return "";
if (i < 3)
	return baseGameTexts [mouseButtonTextIndex [i]][0];
if (i - 3 < (int) sizeofa (extraMouseButtonTextIndex))
	return extraMouseButtonTextIndex [i - 3];
return "";
}

//------------------------------------------------------------------------------

const char* CControlConfig::MouseAxisText (int i)
{
if (i < 0)
	return "";
if (i < (int) sizeofa (mouseAxisTextIndex))
	return baseGameTexts [mouseAxisTextIndex [i]][0];
return "";
}

//------------------------------------------------------------------------------

const char* CControlConfig::YesNoText (int i)
{
return baseGameTexts [yesNoTextIndex [i != 0]][0];
}

//------------------------------------------------------------------------------

int CControlConfig::GetItemHeight (kcItem *item)
{
	int w, h, aw;
	char szText [10];

if (item->value == 255)
	strcpy (szText, "");
else {
	switch (item->nType) {
		case BT_KEY:
			strncpy (szText, (size_t (item->value) < sizeofa (pszKeyText)) ? pszKeyText [item->value] : "", sizeof (szText));
			break;

		case BT_MOUSE_BUTTON:
			strncpy (szText, MouseButtonText (item->value), sizeof (szText));
			break;

		case BT_MOUSE_AXIS:
			strncpy (szText, MouseAxisText (item->value), sizeof (szText));
			break;

		case BT_JOY_BUTTON:
#if defined (USE_LINUX_JOY)
			sprintf (szText, "J%d B%d", j_button [item->value].joydev,
					  j_Get_joydev_button_number (item->value);
#else
		 {
				int	nStick = item->value / MAX_BUTTONS_PER_JOYSTICK;
				int	nBtn = item->value % MAX_BUTTONS_PER_JOYSTICK;
				int	nHat = sdlJoysticks [nStick].nButtons;
				//static char szHatDirs [4] = {'U', 'L', 'D', 'R'};
				static char cHatDirs [4] = { (char) 130, (char) 127, (char) 128, (char) 129};

			if (nBtn < nHat)
				sprintf (szText, "J%d B%d", nStick + 1, nBtn + 1);
			else
				sprintf (szText, "HAT%d%c", nStick + 1, cHatDirs [nBtn - nHat]);
			}
#endif
			break;

		case BT_JOY_AXIS:
#if defined (USE_LINUX_JOY)
			sprintf (szText, "J%d A%d", j_axis [item->value].joydev,
					  j_Get_joydev_axis_number (item->value);
#else
		 {
				int	nStick = item->value / MAX_AXES_PER_JOYSTICK;
				int	nAxis = item->value % MAX_AXES_PER_JOYSTICK;
				static char	cAxis [4] = {'X', 'Y', 'Z', 'R'};

			if (nAxis < 4)
				sprintf (szText, "J%d %c", nStick + 1, cAxis [nAxis]);
			else
				sprintf (szText, "J%d A%d", nStick + 1, nAxis + 1);
			}
#endif
			break;

		case BT_INVERT:
			strncpy (szText, YesNoText (item->value), sizeof (szText));
			break;
		}
	}
fontManager.Current ()->StringSize (szText, w, h, aw);
return h;
}

//------------------------------------------------------------------------------

#define kc_gr_pixel(_x,_y)		DrawPixelClipped ((_x), (_y))
#define KC_LHX(_x) 				(LHX (_x)+m_xOffs)
#define KC_LHY(_y) 				(LHY (_y)+m_yOffs)

void CControlConfig::DrawTitle (void)
{
	char szTitle [200];
	const char *p = strchr (m_pszTitle, '\n');

if (p) {
	int l = (int) (p - m_pszTitle);
	if (l >= (int) sizeof (szTitle))
		l = (int) sizeof (szTitle) - 1;
	memcpy (szTitle, m_pszTitle, l);
	szTitle [l] = '\0';
	p = szTitle;
	}
fontManager.SetCurrent (MEDIUM3_FONT);
GrString (0x8000, KC_LHY (8), p, NULL);
}

//------------------------------------------------------------------------------

void CControlConfig::DrawItem (kcItem *item, int is_current, int bRedraw)
{
	static char cHatDirs [4] = { (char) 130, (char) 127, (char) 128, (char) 129};
	static char	cAxis [4] = {'X', 'Y', 'Z', 'R'};

	int x, w, h, aw;
	char szText [64];

if (bRedraw)
	return;

if (is_current)
	fontManager.SetColorRGBi (RGBA_PAL2 (20,20,29), 1, 0, 0);
else
	fontManager.SetColorRGBi (RGBA_PAL2 (15,15,24), 1, 0, 0);
GrString (KC_LHX (item->x), KC_LHY (item->y), item->textId ? GT (item->textId) : item->text, NULL);

*szText = '\0';
if (item->value != 255) {
	switch (item->nType) {
		case BT_KEY:
			if (size_t (item->value) < sizeofa (pszKeyText))
				strncat (szText, pszKeyText [item->value], 10);
			break;

		case BT_MOUSE_BUTTON:
			//strncpy (szText, baseGameTexts [mouseButtonTextIndex [item->value]], 10); break;
			strncpy (szText, MouseButtonText (item->value), 10);
			break;

		case BT_MOUSE_AXIS:
			strncpy (szText, MouseAxisText (item->value), 10);
			break;

		case BT_JOY_BUTTON: {
#ifdef USE_LINUX_JOY
			sprintf (szText, "J%d B%d",
					  j_button [item->value].joydev, j_Get_joydev_button_number (item->value);
#else
				int	nStick = item->value / MAX_BUTTONS_PER_JOYSTICK;
				int	nBtn = item->value % MAX_BUTTONS_PER_JOYSTICK;
				int	nHat = sdlJoysticks [nStick].nButtons;
				//static char szHatDirs [4] = {'U', 'L', 'D', 'R'};
			if (nBtn < nHat)
				sprintf (szText, "J%d B%d", nStick + 1, nBtn + 1);
			else
				sprintf (szText, "HAT%d%c", nStick + 1, cHatDirs [nBtn - nHat]);
#endif
			}
			break;

		case BT_JOY_AXIS: {
#if defined (USE_LINUX_JOY)
			sprintf (szText, "J%d A%d", j_axis [item->value].joydev, j_Get_joydev_axis_number (item->value));
#elif 1//defined (_WIN32)
				int	nStick = item->value / MAX_AXES_PER_JOYSTICK;
				int	nAxis = item->value % MAX_AXES_PER_JOYSTICK;

			if (nAxis < 4)
				sprintf (szText, "J%d %c", nStick + 1, cAxis [nAxis]);
			else
				sprintf (szText, "J%d A%d", nStick + 1, nAxis + 1);
#else
			strncpy (szText, baseGameTexts [JOYAXIS_TEXT (item->value)], 10);
#endif
			}
			break;

		case BT_INVERT:
			strncpy (szText, YesNoText (item->value), 10);
			break;
		}
	}

if (item->w1) {
	fontManager.Current ()->StringSize (szText, w, h, aw);

	if (is_current)
		CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (21, 0, 24));
	else
		CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (16, 0, 19));
	OglDrawFilledRect (KC_LHX (item->x + item->w1), KC_LHY (item->y - 1),
				KC_LHX (item->x + item->w1 + item->w2), KC_LHY (item->y) + h);
	fontManager.SetColorRGBi (RGBA_PAL2 (28, 28, 28), 1, 0, 0);
	x = LHX (item->w1 + item->x) + ((LHX (item->w2) - w) / 2) + m_xOffs;
	GrString (x, KC_LHY (item->y), szText, NULL);
	}
}

//------------------------------------------------------------------------------

void CControlConfig::DrawHeader (void)
{
fontManager.SetCurrent (GAME_FONT);
fontManager.SetColorRGBi (RGBA_PAL2 (28, 28, 28), 1, 0, 0);

GrString (0x8000, KC_LHY (20), TXT_KCONFIG_STRING_1, NULL);
fontManager.SetColorRGBi (RGBA_PAL2 (28, 28, 28), 1, 0, 0);
if (m_items == kcKeyboard) {
	fontManager.SetColorRGBi (RGBA_PAL2 (31, 27, 6), 1, 0, 0);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (31, 27, 6));
	OglDrawLine (KC_LHX (98), KC_LHY (42), KC_LHX (106), KC_LHY (42));
	OglDrawLine (KC_LHX (120), KC_LHY (42), KC_LHX (128), KC_LHY (42));
	kc_gr_pixel (KC_LHX (98), KC_LHY (43));
	kc_gr_pixel (KC_LHX (98), KC_LHY (44));
	kc_gr_pixel (KC_LHX (128), KC_LHY (43));
	kc_gr_pixel (KC_LHX (128), KC_LHY (44));

	GrString (KC_LHX (109), KC_LHY (40), "OR", NULL);

	OglDrawLine (KC_LHX (253), KC_LHY (42), KC_LHX (261), KC_LHY (42));
	OglDrawLine (KC_LHX (274), KC_LHY (42), KC_LHX (283), KC_LHY (42));
	kc_gr_pixel (KC_LHX (253), KC_LHY (43));
	kc_gr_pixel (KC_LHX (253), KC_LHY (44));
	kc_gr_pixel (KC_LHX (283), KC_LHY (43));
	kc_gr_pixel (KC_LHX (283), KC_LHY (44));

	GrString (KC_LHX (264), KC_LHY (40), "OR", NULL);
	}
else if (m_items == kcJoystick) {
	fontManager.SetColorRGBi (RGBA_PAL2 (31,27,6), 1, 0, 0);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (31, 27, 6));
	OglDrawLine (KC_LHX (18), KC_LHY (37), KC_LHX (116), KC_LHY (37));
	OglDrawLine (KC_LHX (200), KC_LHY (37), KC_LHX (294), KC_LHY (37));
	OglDrawLine (KC_LHX (18), KC_LHY (127+18), KC_LHX (144), KC_LHY (127+18));
	OglDrawLine (KC_LHX (174), KC_LHY (127+18), KC_LHX (294), KC_LHY (127+18));
	GrString (0x8000, KC_LHY (35), TXT_BUTTONS_HATS, NULL);
	GrString (0x8000,KC_LHY (125+18), TXT_AXES, NULL);
	fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 0);
	GrString (KC_LHX (85), KC_LHY (145+8), TXT_AXIS, NULL);
	GrString (KC_LHX (120), KC_LHY (145+8), TXT_INVERT, NULL);
	GrString (KC_LHX (235), KC_LHY (145+8), TXT_AXIS, NULL);
	GrString (KC_LHX (270), KC_LHY (145+8), TXT_INVERT, NULL);
	}
else if (m_items == kcMouse) {
	fontManager.SetColorRGBi (RGBA_PAL2 (31,27,6), 1, 0, 0);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (31,27,6));
	OglDrawLine (KC_LHX (18), KC_LHY (37), KC_LHX (135), KC_LHY (37));
	OglDrawLine (KC_LHX (181), KC_LHY (37), KC_LHX (294), KC_LHY (37));
	OglDrawLine (KC_LHX (18), KC_LHY (127+5), KC_LHX (144), KC_LHY (127+5));
	OglDrawLine (KC_LHX (174), KC_LHY (127+5), KC_LHX (294), KC_LHY (127+5));
	GrString (0x8000, KC_LHY (35), TXT_BUTTONS, NULL);
	GrString (0x8000,KC_LHY (125+5), TXT_AXES, NULL);
	fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 0);
	GrString (KC_LHX (169), KC_LHY (137), TXT_AXIS, NULL);
	GrString (KC_LHX (199), KC_LHY (137), TXT_INVERT, NULL);
	}
else if (m_items == kcHotkeys) {
	fontManager.SetColorRGBi (RGBA_PAL2 (31,27,6), 1, 0, 0);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (31, 27, 6));

	GrString (KC_LHX (94), KC_LHY (40), "KB", NULL);
	GrString (KC_LHX (121), KC_LHY (40), "JOY", NULL);
	}
}

//------------------------------------------------------------------------------

void CControlConfig::DrawTable (void)
{
	int	i;

for (i = 0; i < m_nItems; i++)
	DrawItem (m_items + i, 0, 0);
DrawItem (m_items + m_nCurItem, 1, 0);
}

//------------------------------------------------------------------------------

void CControlConfig::Render (void)
{
if (gameOpts->menus.nStyle && gameStates.app.bGameRunning)
	RenderMenuGameFrame ();

if (BeginRenderMenu ()) {
	CCanvas::SetCurrent (backgroundManager.Canvas ());
	backgroundManager.Redraw ();
	CCanvas::SetCurrent (NULL);
	DrawTitle ();
	m_closeX = m_closeY = gameStates.menus.bHires ? 15 : 7;
	m_closeX += m_xOffs;
	m_closeY += m_yOffs;
	m_closeSize = gameStates.menus.bHires?10:5;
	CCanvas::Current ()->SetColorRGB (0, 0, 0, 255);
	OglDrawFilledRect (m_closeX, m_closeY, m_closeX + m_closeSize, m_closeY + m_closeSize);
	CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (21, 21, 21));
	OglDrawFilledRect (m_closeX + LHX (1), m_closeY + LHX (1), m_closeX + m_closeSize - LHX (1), m_closeY + m_closeSize - LHX (1));
	DrawHeader ();
	DrawTable ();
	SDL_ShowCursor (0);
	m_bRedraw = 1;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::DrawQuestion (kcItem *item)
{
	static int looper = 0;

	int x, w, h, aw;

fontManager.Current ()->StringSize ("?", w, h, aw);
CCanvas::Current ()->SetColorRGBi (RGBA_PAL2 (21*fades [looper]/31, 0, 24*fades [looper]/31));
if (++looper>63)
	looper=0;
OglDrawFilledRect (KC_LHX (item->w1 + item->x), KC_LHY (item->y - 1),
						 KC_LHX (item->w1 + item->x + item->w2), KC_LHY (item->y) + h);
fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 0);
x = LHX (item->w1+item->x)+ ((LHX (item->w2)-w)/2)+m_xOffs;
GrString (x, KC_LHY (item->y), "?", NULL);
if (ogl.m_states.nDrawBuffer != GL_BACK)
	GrUpdate (1);
}

//------------------------------------------------------------------------------

void CControlConfig::Quit (void)
{
CCanvas::Pop ();
//bg->menu_canvas = NULL;
GameFlushInputs ();
backgroundManager.Remove ();
SDL_ShowCursor (0);
if (m_bTimeStopped)
	StartTime (0);
gameStates.menus.nInMenu--;
paletteManager.SetEffect (0, 0, 0);
}

//------------------------------------------------------------------------------

int CControlConfig::AssignControl (kcItem *item, int nType, ubyte code)
{
	int	i, n;

if (code == 255)
	return nType;

for (i = 0, n = (int) (item - m_items); i < m_nItems; i++) {
	if ((i != n) && (m_items [i].nType == nType) && (m_items [i].value == code)) {
		m_items [i].value = 255;
		if (ogl.m_states.nDrawBuffer == GL_FRONT)
			DrawItem (m_items + i, 0);
		}
	}
item->value = code;
if (ogl.m_states.nDrawBuffer == GL_FRONT) {
	DrawItem (item, 1);
	backgroundManager.Restore (m_xOffs, m_yOffs, KC_LHX (310), CCanvas::Current ()->Font ()->Height (), 0, KC_LHY (INFO_Y));
	}
GameFlushInputs ();
fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 1);
return BT_NONE;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::KeyCtrlFunc (void)
{
	int	i, n, f;

for (i = 0; i < 256; i++) {
	if (gameStates.input.keys.pressed [i] && strlen (pszKeyText [i])) {
		f = 0;
		for (n = 0; n < (int) sizeof (system_keys); n++)
			if (system_keys [n] == i)
				f = 1;
		if (!f)
			return (ubyte) i;
		}
	}
return 255;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::JoyBtnCtrlFunc (void)
{
	int	i;
	ubyte code = 255;

if (gameStates.input.nJoyType == CONTROL_THRUSTMASTER_FCS) {
	int axis [JOY_MAX_AXES];
	JoyReadRawAxis (JOY_ALL_AXIS, axis);
	controls.ReadFCS (axis [3]);
	if (JoyGetButtonState (19))
		code = 19;
	else if (JoyGetButtonState (15))
		code = 15;
	else if (JoyGetButtonState (11))
		code = 11;
	else if (JoyGetButtonState (7))
		code = 7;
	for (i = 0; i < 4; i++)
		if (JoyGetButtonState (i))
			return (ubyte) i;
	}
else if (gameStates.input.nJoyType == CONTROL_FLIGHTSTICK_PRO) {
	for (i = 4; i < 20; i++) {
		if (JoyGetButtonState (i))
			return (ubyte) i;
		}
	}
else {
	for (i = 0; i < JOY_MAX_BUTTONS; i++) {
		if (JoyGetButtonState (i))
			return (ubyte) i;
		}
	}
return code;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::MouseBtnCtrlFunc (void)
{
int i, b = MouseGetButtons ();
for (i = 0; i < 16; i++)
	if (b & (1 << i))
		return (ubyte) i;
return 255;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::JoyAxisCtrlFunc (void)
{
	int curAxis [JOY_MAX_AXES];
	int i, hd, dd;
	int bLinJoySensSave = gameOpts->input.joystick.bLinearSens;
	ubyte code = 255;

memset (curAxis, 0, sizeof (curAxis));
gameOpts->input.joystick.bLinearSens = 1;
controls.SetPollTime (128);
controls.ReadJoystick (curAxis);
gameOpts->input.joystick.bLinearSens = bLinJoySensSave;
for (i = dd = 0; i < JOY_MAX_AXES; i++) {
	hd = abs (curAxis [i]); // - m_startAxis [i]);
  	if ((hd > (128 * 3 / 4)) && (hd > dd)) {
		dd = hd;
		code = i;
		m_startAxis [i] = curAxis [i];
		}
	}
return code;
}

//------------------------------------------------------------------------------

ubyte CControlConfig::MouseAxisCtrlFunc (void)
{
	int dx, dy;
#ifdef SDL_INPUT
	int dz;
#endif
	ubyte code = 255;

#ifdef SDL_INPUT
MouseGetDeltaZ (&dx, &dy, &dz);
#else
MouseGetDelta (&dx, &dy);
#endif
console.printf (CON_VERBOSE, "mouse: %3d %3d\n", dx, dy);
dx = abs (dx);
dy = abs (dy);
if (max (dx, dy) > 20) {
	code = dy > dx;
	}
#ifdef SDL_INPUT
dz = abs (dz);
if ((dz > 20) && (dz > code ? dy : dx))
	code = 2;
#endif
return code;
}

//------------------------------------------------------------------------------

int CControlConfig::ChangeControl (kcItem *item, int nType, kc_ctrlfunc_ptr ctrlfunc, const char *pszMsg)
{
	int k = 255;

	fontManager.SetColorRGBi (RGBA_PAL2 (28,28,28), 1, 0, 0);
	GrString (0x8000, KC_LHY (INFO_Y), pszMsg, NULL);
{
	if ((gameData.app.nGameMode & GM_MULTI) && (gameStates.app.nFunctionMode == FMODE_GAME) && (!gameStates.app.bEndLevelSequence))
		MultiMenuPoll ();
	k = KeyInKey ();
	if (k == KEY_ESC)
		return AssignControl (item, BT_NONE, 255);
	if (k == KEY_PRINT_SCREEN) {
		SaveScreenShot (NULL, 0);
		return AssignControl (item, BT_NONE, 255);
		}
	if (ogl.m_states.nDrawBuffer == GL_FRONT)
		G3_SLEEP (10);
	DrawQuestion (item);
	}
return AssignControl (item, nType, ctrlfunc ());
}

//------------------------------------------------------------------------------

int CControlConfig::ChangeInvert (kcItem * item)
{
GameFlushInputs ();
item->value = !item->value;
if (ogl.m_states.nDrawBuffer == GL_FRONT)
	DrawItem (item, 1);
return BT_NONE;
}

//------------------------------------------------------------------------------

void CControlConfig::QSortItemPos (tItemPos *pos, int left, int right)
{
	int			l = left,
					r = right;
	tItemPos	h, m = pos [(l + r) / 2];

do {
	while ((pos [l].y < m.y) || ((pos [l].y == m.y) && (pos [l].l < m.l)))
		l++;
	while ((pos [r].y > m.y) || ((pos [r].y == m.y) && (pos [r].l > m.l)))
		r--;
	if (l <= r) {
		if (l < r) {
			h = pos [l];
			pos [l] = pos [r];
			pos [r] = h;
			}
		l++;
		r--;
		}
	} while (l <= r);
if (l < right)
	QSortItemPos (pos, l, right);
if (left < r)
	QSortItemPos (pos, left, r);
}

//------------------------------------------------------------------------------

CControlConfig::tItemPos* CControlConfig::GetItemPos (kcItem* items, int nItems)
{
	tItemPos	*pos;
	int			i;

if (!(pos = new tItemPos [nItems]))
	return NULL;
for (i = 0; i < nItems; i++) {
	pos [i].l = items [i].x + items [i].w1;
	pos [i].r = pos [i].l + items [i].w2;
	pos [i].y = items [i].y;
	pos [i].i = i;
	}
QSortItemPos (pos, 0, nItems - 1);
return pos;
}

//------------------------------------------------------------------------------

int* CControlConfig::GetItemRef (int nItems, tItemPos* pos)
{
	int	*ref;
	int	i;

if (!(ref = new int [nItems]))
	return NULL;
for (i = 0; i < nItems; i++)
	ref [pos [i].i] = i;
return ref;
}

//------------------------------------------------------------------------------

void CControlConfig::LinkKbdEntries (void)
{
	int			i, j, *ref;
	tItemPos*	pos = GetItemPos (kcKeyboard, NUM_KEY_CONTROLS);

if (pos) {
	if ((ref = GetItemRef (NUM_KEY_CONTROLS, pos))) {
		for (i = 0, j = NUM_KEY_CONTROLS; i < j; i++) {
			kcKeyboard [i].u = FindNextItemUp (j, i, pos, ref);
			kcKeyboard [i].d = FindNextItemDown (j, i, pos, ref);
			kcKeyboard [i].l = FindNextItemLeft (j, i, pos, ref);
			kcKeyboard [i].r = FindNextItemRight (j, i, pos, ref);
			}
		delete[] ref;
		}
	delete[] pos;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::LinkJoyEntries (void)
{
	int			i, j, *ref;
	tItemPos*	pos = GetItemPos (kcJoystick, NUM_JOY_CONTROLS);

if (pos) {
	if ((ref = GetItemRef (NUM_JOY_CONTROLS, pos))) {
		for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++) {
			kcJoystick [i].u = FindNextItemUp (j, i, pos, ref);
			kcJoystick [i].d = FindNextItemDown (j, i, pos, ref);
			kcJoystick [i].l = FindNextItemLeft (j, i, pos, ref);
			kcJoystick [i].r = FindNextItemRight (j, i, pos, ref);
			}
		delete[] ref;
		}
	delete[] pos;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::LinkMouseEntries (void)
{
	int			i, j, *ref;
	tItemPos*	pos = GetItemPos (kcMouse, NUM_MOUSE_CONTROLS);

if (pos) {
	if ((ref = GetItemRef (NUM_MOUSE_CONTROLS, pos))) {
		for (i = 0, j = NUM_MOUSE_CONTROLS; i < j; i++) {
			kcMouse [i].u = FindNextItemUp (j, i, pos, ref);
			kcMouse [i].d = FindNextItemDown (j, i, pos, ref);
			kcMouse [i].l = FindNextItemLeft (j, i, pos, ref);
			kcMouse [i].r = FindNextItemRight (j, i, pos, ref);
			}
		delete[] ref;
		}
	delete[] pos;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::LinkHotkeyEntries (void)
{
	int			i, j, *ref;
	tItemPos*	pos = GetItemPos (kcHotkeys, NUM_HOTKEY_CONTROLS);

if (pos) {
	if ((ref = GetItemRef (NUM_HOTKEY_CONTROLS, pos))) {
		for (i = 0, j = NUM_HOTKEY_CONTROLS; i < j; i++) {
			kcHotkeys [i].u = FindNextItemUp (j, i, pos, ref);
			kcHotkeys [i].d = FindNextItemDown (j, i, pos, ref);
			kcHotkeys [i].l = FindNextItemLeft (j, i, pos, ref);
			kcHotkeys [i].r = FindNextItemRight (j, i, pos, ref);
			}
		delete[] ref;
		}
	delete[] pos;
	}
}

//------------------------------------------------------------------------------

void CControlConfig::LinkTableEntries (int tableFlags)
{
	static int nLinked = 0;

if ((tableFlags & 1) && !(nLinked & 1))
	LinkKbdEntries ();
if ((tableFlags & 2) && !(nLinked & 2))
	LinkJoyEntries ();
if ((tableFlags & 4) && !(nLinked & 4))
	LinkMouseEntries ();
if ((tableFlags & 8) && !(nLinked & 8))
	LinkHotkeyEntries ();
nLinked |= tableFlags;
}

//------------------------------------------------------------------------------

int CControlConfig::HandleControl (void)
{
m_nPrevChangeMode = m_nChangeMode;
do {
	Render ();

	switch (m_nChangeMode) {
		case BT_KEY:
			m_nChangeMode = ChangeKey (m_items + m_nCurItem);
			break;
		case BT_MOUSE_BUTTON:
			m_nChangeMode = ChangeMouseButton (m_items + m_nCurItem);
			break;
		case BT_MOUSE_AXIS:
			m_nChangeMode = ChangeMouseAxis (m_items + m_nCurItem);
			break;
		case BT_JOY_BUTTON:
			m_nChangeMode = ChangeJoyButton (m_items + m_nCurItem);
			break;
		case BT_JOY_AXIS:
			//if (m_nChangeMode != m_nPrevChangeMode)
				controls.ReadJoystick (m_startAxis);
			m_nChangeMode = ChangeJoyAxis (m_items + m_nCurItem);
			break;
		case BT_INVERT:
			m_nChangeMode = ChangeInvert (m_items + m_nCurItem);
			break;
		default:
			m_nChangeMode = BT_NONE;
		}
	m_nPrevChangeMode = m_nChangeMode;
	SDL_ShowCursor (1);
	if (m_bRedraw) {
		GrUpdate (1);
		if (gameStates.app.bGameRunning)
			ogl.ChooseDrawBuffer ();
		m_bRedraw = 0;
		}
	} while (m_nChangeMode != BT_NONE);
return m_nChangeMode;
}

//------------------------------------------------------------------------------

int CControlConfig::HandleInput (void)
{
	int		i, k;

k = KeyInKey ();
if (!m_bTimeStopped && (MultiMenuPoll () == -1))
	return -1;

m_nPrevItem = m_nCurItem;
switch (k) {
	case KEY_BACKSPACE:
		break;

	case KEY_COMMAND+KEY_SHIFTED+KEY_P:
	case KEY_PRINT_SCREEN:
		SaveScreenShot (NULL, 0);
		break;

	case KEY_CTRLED+KEY_D:
		m_items [m_nCurItem].value = 255;
		DrawItem (m_items + m_nCurItem, 1);
		break;

	case KEY_CTRLED+KEY_R:
		if (m_items == kcKeyboard) {
			for (i = 0; i < NUM_KEY_CONTROLS; i++) {
				m_items [i].value = controlSettings.defaults [0][i];
				DrawItem (m_items + i, 0);
				}
			}
		else if (m_items == kcHotkeys) {
			for (i = 0; i < NUM_HOTKEY_CONTROLS; i++) {
				m_items [i].value = controlSettings.d2xDefaults [i];
				DrawItem (m_items + i, 0);
				}
			}
		else if (m_items == kcMouse) {
			for (i = 0; i < NUM_MOUSE_CONTROLS; i++) {
				m_items [i].value = controlSettings.defaults [gameConfig.nControlType][i];
				DrawItem (m_items + i, 0);
				}
			}
		else {
			for (i = 0; i < NUM_JOY_CONTROLS; i++) {
				m_items [i].value = controlSettings.defaults [gameConfig.nControlType][i];
				DrawItem (m_items + i, 0);
				}
			}
		DrawItem (m_items + m_nCurItem, 1);
		break;

	case KEY_DELETE:
		m_items [m_nCurItem].value = 255;
		DrawItem (m_items + m_nCurItem, 1);
		break;

	case KEY_UP:
	case KEY_PAD8:
		m_nCurItem = m_items [m_nCurItem].u;
		break;

	case KEY_DOWN:
	case KEY_PAD2:
		m_nCurItem = m_items [m_nCurItem].d;
		break;

	case KEY_LEFT:
	case KEY_PAD4:
		m_nCurItem = m_items [m_nCurItem].l;
		break;

	case KEY_RIGHT:
	case KEY_PAD6:
		m_nCurItem = m_items [m_nCurItem].r;
		break;

	case KEY_ENTER:
	case KEY_PADENTER:
		m_nChangeMode = m_items [m_nCurItem].nType;
		GameFlushInputs ();
		break;

	case KEY_ESC:
		return -1;
	}

m_nPrevMouseState = m_nMouseState;
m_nMouseState = MouseButtonState (0);
if ((m_nMouseState && !m_nPrevMouseState) || (m_nMouseState && m_nPrevMouseState)) {
	int item_height, mx, my;
	MouseGetPos (&mx, &my);
	mx -= m_xOffs;
	my -= m_yOffs;
//			my = (my * 12) / 10;	//y mouse pos is off here, no clue why
	for (i = 0; i < m_nItems; i++) {
		item_height = GetItemHeight (m_items + i);
		int x1 = CCanvas::Current ()->Left () + LHX (m_items [i].x) + LHX (m_items [i].w1);
		int x2 = x1 + LHX (m_items [i].w2);
		int y1 = CCanvas::Current ()->Top () + LHY (m_items [i].y);
		int y2 = y1 + /*LHY*/ (item_height);
		if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) {
			m_nCurItem = i;
			break;
			}
		}
	}
else if (!m_nMouseState && m_nPrevMouseState) {
	int item_height, mx, my;

	MouseGetPos (&mx, &my);
	mx -= m_xOffs;
	my -= m_yOffs;
	my = (my * 12) / 10;	//y mouse pos is off here, no clue why
	item_height = GetItemHeight (m_items + m_nCurItem);
	int x1 = CCanvas::Current ()->Left () + LHX (m_items [m_nCurItem].x) + LHX (m_items [m_nCurItem].w1);
	int x2 = x1 + LHX (m_items [m_nCurItem].w2);
	int y1 = CCanvas::Current ()->Top () + LHY (m_items [m_nCurItem].y);
	int y2 = y1 + /*LHY*/ (item_height);
	if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) {
		m_nChangeMode = m_items [m_nCurItem].nType;
		GameFlushInputs ();
		}
	else {
		int x1 = CCanvas::Current ()->Left () + m_closeX + LHX (1);
		int x2 = x1 + m_closeSize - LHX (1);
		int y1 = CCanvas::Current ()->Top () + m_closeY + LHX (1);
		int y2 = y1 + m_closeSize - LHY (1);
		if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) {
			return -1;
			}
		}
	}
return m_nCurItem;
}

//------------------------------------------------------------------------------

void CControlConfig::Edit (kcItem* items, int nItems)
{
	int i;

m_items = items;
m_nItems = nItems;
m_nPrevItem = -1;
m_nCurItem = 0;
m_nPrevMouseState =
m_nMouseState = 0;
m_nPrevChangeMode = 
m_nChangeMode = BT_NONE;
m_bTimeStopped = 0;
m_bRedraw = 0;
m_pszTitle = m_pszTitle;

paletteManager.SetEffect (0, 0, 0);
gameStates.menus.nInMenu++;
memset (m_startAxis, 0, sizeof (m_startAxis));

if (!IsMultiGame || (gameStates.app.nFunctionMode != FMODE_GAME) || gameStates.app.bEndLevelSequence) {
	m_bTimeStopped = 1;
	StopTime ();
	}

CCanvas::Push ();
CCanvas::SetCurrent (NULL);
CFont* font = CCanvas::Current ()->Font ();
controls.FlushInput ();
backgroundManager.Setup (NULL, m_xOffs, m_yOffs, 640, 480);
//paletteManager.ResumeEffect ();
CCanvas::SetCurrent (NULL);

SDL_ShowCursor (1);
if (m_items == kcKeyboard)
	i = 0;
else if (m_items == kcJoystick)
	i = 1;
else if (m_items == kcMouse)
	i = 2;
else if (m_items == kcHotkeys)
	i = 3;
else
	i = -1;
if (i >= 0)
	LinkTableEntries (1 << i);

for (;;) {
	m_nChangeMode = HandleControl ();
	redbook.CheckRepeat ();
	MultiDoFrame ();
	m_nPrevItem = m_nCurItem;
	if (0 > (m_nCurItem = HandleInput ())) {
		Quit ();
		return;
		}
	if (m_nPrevItem != m_nCurItem) {
		SDL_ShowCursor (0);
		DrawItem (m_items + m_nPrevItem, 0);
		DrawItem (m_items + m_nCurItem, 1);
		SDL_ShowCursor (1);
		}
	}
Quit ();
}

//------------------------------------------------------------------------------

#include "screens.h"

void CControlConfig::Run (int nType, const char* pszTitle)
{
CBitmap*	bmSave;
int		i, j, b = gameOpts->legacy.bInput;

m_pszTitle = pszTitle;
m_xOffs = (CCanvas::Current ()->Width () - 640) / 2;
m_yOffs = (CCanvas::Current ()->Height () - 480) / 2;
if (m_xOffs < 0)
	m_xOffs = 0;
if (m_yOffs < 0)
	m_yOffs = 0;

gameOpts->legacy.bInput = 1;
SetScreenMode (SCREEN_MENU);
KCSetControls (0);
//save screen
if (gameOpts->menus.bFastMenus)
	bmSave = NULL;
else {
	bmSave = CBitmap::Create (0, CCanvas::Current ()->Width (), CCanvas::Current ()->Height (), 1);
	Assert (bmSave != NULL);
	bmSave->SetPalette (paletteManager.Texture ());
	CCanvas::Current ()->BlitClipped (bmSave, 0, 0, CCanvas::Current ()->Width (), CCanvas::Current ()->Width (), 0, 0);
	}
if (nType == 0)
	Edit (kcKeyboard, NUM_KEY_CONTROLS);
else if (nType == 1)
	Edit (kcJoystick, NUM_JOY_CONTROLS);
else if (nType == 2)
	Edit (kcMouse, NUM_MOUSE_CONTROLS);
#if 0
else if (nType == 3)
	Edit (kcSuperJoy, NUM_JOY_CONTROLS);
#endif
else if (nType == 4)
	Edit (kcHotkeys, NUM_HOTKEY_CONTROLS);
//end this section addition - VR
else {
	Int3 ();
	gameOpts->legacy.bInput = b;
	return;
	}

//restore screen
if (bmSave) {
	bmSave->BlitClipped (m_xOffs, m_yOffs);
	delete bmSave;
	}
// Update save values...
if (nType == 0) {
	for (i = 0, j = NUM_KEY_CONTROLS; i < j; i++)
		controlSettings.custom [0][i] = kcKeyboard [i].value;
	}
else if (nType == 1) {
	if (gameOpts->input.joystick.bUse)
		for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++)
			controlSettings.custom [gameStates.input.nJoyType][i] = kcJoystick [i].value;
	}
else if (nType == 2) {
	if (gameOpts->input.mouse.bUse)
		for (i = 0, j = NUM_MOUSE_CONTROLS; i < j; i++)
			controlSettings.custom [gameStates.input.nMouseType][i] = kcMouse [i].value;
	}
else if (nType == 3) {
	if (gameConfig.nControlType == CONTROL_WINJOYSTICK)
		for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++)
			controlSettings.custom [gameConfig.nControlType][i] = kcSuperJoy [i].value;
	}
else if (nType == 4) {
	for (i=0, j = NUM_HOTKEY_CONTROLS; i < j; i++)
		controlSettings.d2xCustom [i] = kcHotkeys [i].value;
	}
gameOpts->legacy.bInput = b;
}

//------------------------------------------------------------------------------

fix Last_angles_p = 0;
fix Last_angles_b = 0;
fix Last_angles_h = 0;
ubyte Last_angles_read = 0;

int VR_sense_range [3] = { 25, 50, 75 };

#if 0
read_head_tracker ()
{
	fix yaw, pitch, roll;
	int buttons;

//------ read vfx1 helmet --------
	if (vfx1_installed) {
		vfx_get_data (&yaw,&pitch,&roll,&buttons);
	} else if (iglasses_headset_installed) {
		iglasses_read_headset (&yaw, &pitch, &roll);
	} else if (Victor_headset_installed)   {
		victor_read_headset_filtered (&yaw, &pitch, &roll);
	} else {
		return;
	}

	transformation.m_info.bUsePlayerHeadAngles = 0;
	if (Last_angles_read) {
		fix yaw1 = yaw;

		yaw1 = yaw;
		if ((Last_angles_h < (I2X (1)/4)) && (yaw > ((I2X (3))/4)))
			yaw1 -= I2X (1);
		else if ((yaw < (I2X (1)/4)) && (Last_angles_h > ((I2X (3))/4)))
			yaw1 += I2X (1);

		controls [0].pitchTime	+= FixMul ((pitch- Last_angles_p)*VR_sense_range [gameStates.render.vr.nSensitivity],gameData.time.xFrame);
		controls [0].headingTime+= FixMul ((yaw1 -  Last_angles_h)*VR_sense_range [gameStates.render.vr.nSensitivity],gameData.time.xFrame);
		controls [0].bankTime	+= FixMul ((roll - Last_angles_b)*VR_sense_range [gameStates.render.vr.nSensitivity],gameData.time.xFrame);
	}
	Last_angles_read = 1;
	Last_angles_p = pitch;
	Last_angles_h = yaw;
	Last_angles_b = roll;
}
#endif

//------------------------------------------------------------------------------

void CExternalControls::Init (int intno, int address)
{
	int i;
	m_intno = intno;
	m_info = reinterpret_cast<ext_control_info*> ((size_t) address);
	m_bUse = 1;
	m_bEnable  = 1;

	i = FindArg ("-xname");
	if (i)
		m_name = StrDup (pszArgList [i + 1]);
	else
		m_name = StrDup ("External Controller");

   for (i = 0; i < (int) strlen (reinterpret_cast<char*> (m_name)); i++)
    if (m_name [i]=='_')
	  m_name [i]=' ';

	i = FindArg ("-xver");
	if (i)
		m_version = atoi (pszArgList [i+1]);
}

//------------------------------------------------------------------------------

void CExternalControls::Read (void)
{
	//union REGS r;
   int i;

	if (!m_bEnable) return;

if (m_version == 0)
	memset (m_info, 0, sizeof (ext_control_info));
else if (m_version > 0)  {

	if (m_version>=4)
		memset (m_info, 0, sizeof (advanced_ext_control_info));
   else if (m_version>0)
		memset (m_info, 0, sizeof (ext_control_info)+sizeof (CAngleVector) + 64);
	else if (m_version>2)
		memset (m_info, 0, sizeof (ext_control_info)+sizeof (CAngleVector) + 64 + sizeof (CFixVector) + sizeof (CFixMatrix) +4);

	if (m_version > 1) {
		// Write ship pos and angles to external controls...
		ubyte *temp_ptr = reinterpret_cast<ubyte*> (m_info);
		CFixVector *ship_pos;
		CFixMatrix *ship_orient;
		memset (m_info, 0, sizeof (ext_control_info)+sizeof (CAngleVector) + 64 + sizeof (CFixVector)+sizeof (CFixMatrix));
		temp_ptr += sizeof (ext_control_info) + sizeof (CAngleVector) + 64;
		ship_pos = reinterpret_cast<CFixVector*> (temp_ptr);
		temp_ptr += sizeof (CFixVector);
		ship_orient = reinterpret_cast<CFixMatrix*> (temp_ptr);
		// Fill in ship postion...
		*ship_pos = OBJECTS [LOCALPLAYER.nObject].info.position.vPos;
		// Fill in ship orientation...
		*ship_orient = OBJECTS [LOCALPLAYER.nObject].info.position.mOrient;
		}
    if (m_version>=4) {
	   advanced_ext_control_info *temp_ptr = reinterpret_cast<advanced_ext_control_info*> (m_info);

      temp_ptr->headlightState = PlayerHasHeadlight (-1);
		temp_ptr->primaryWeaponFlags = LOCALPLAYER.primaryWeaponFlags;
		temp_ptr->secondaryWeaponFlags = LOCALPLAYER.secondaryWeaponFlags;
      temp_ptr->currentPrimary_weapon = gameData.weapons.nPrimary;
      temp_ptr->currentSecondary_weapon = gameData.weapons.nSecondary;
      temp_ptr->current_guidebot_command = gameData.escort.nGoalObject;
	   temp_ptr->force_vector=ExtForceVec;
		temp_ptr->force_matrix=ExtApplyForceMatrix;
	   for (i=0;i<3;i++)
       temp_ptr->joltinfo [i]=ExtJoltInfo [i];
      for (i=0;i<2;i++)
		   temp_ptr->x_vibrate_info [i]=ExtXVibrateInfo [i];
		temp_ptr->x_vibrate_clear=ExtXVibrateClear;
 	   temp_ptr->gameStatus=gameStates.app.nExtGameStatus;

      memset (&ExtForceVec, 0, sizeof (CFixVector));
      memset (&ExtApplyForceMatrix, 0, sizeof (CFixMatrix));

      for (i=0;i<3;i++)
		 ExtJoltInfo [i]=0;
      for (i=0;i<2;i++)
		 ExtXVibrateInfo [i]=0;
      ExtXVibrateClear=0;
		}
	}

	if (automap.Display ())			// (If in automap...)
		m_info->automapState = 1;
	//memset (&r,0,sizeof (r);

	if (gameData.multiplayer.nLocalPlayer > -1) {
		OBJECTS [LOCALPLAYER.nObject].mType.physInfo.flags &= (~PF_TURNROLL);	// Turn off roll when turning
		OBJECTS [LOCALPLAYER.nObject].mType.physInfo.flags &= (~PF_LEVELLING);	// Turn off leveling to nearest CSide.
		gameOpts->gameplay.nAutoLeveling = 0;

		if (m_version > 0) {
			CFixMatrix tempm, ViewMatrix;
			CAngleVector * Kconfig_abs_movement;
			char * oem_message;

			Kconfig_abs_movement = reinterpret_cast<CAngleVector*> ((size_t) m_info + sizeof (ext_control_info));

			if (!Kconfig_abs_movement->IsZero ()) {
				tempm = CFixMatrix::Create(*Kconfig_abs_movement);
				ViewMatrix = OBJECTS [LOCALPLAYER.nObject].info.position.mOrient * tempm;
				OBJECTS [LOCALPLAYER.nObject].info.position.mOrient = ViewMatrix;
			}
			oem_message = reinterpret_cast<char*> ((size_t) Kconfig_abs_movement + sizeof (CAngleVector));
			if (oem_message [0] != '\0')
				HUDInitMessage (oem_message);
		}
	}

	controls [0].pitchTime += FixMul (m_info->pitchTime,gameData.time.xFrame);
	controls [0].verticalThrustTime += FixMul (m_info->verticalThrustTime,gameData.time.xFrame);
	controls [0].headingTime += FixMul (m_info->headingTime,gameData.time.xFrame);
	controls [0].sidewaysThrustTime += FixMul (m_info->sidewaysThrustTime, gameData.time.xFrame);
	controls [0].bankTime += FixMul (m_info->bankTime, gameData.time.xFrame);
	controls [0].forwardThrustTime += FixMul (m_info->forwardThrustTime, gameData.time.xFrame);
	controls [0].rearViewDownCount += m_info->rearViewDownCount;
	controls [0].rearViewDownState |= m_info->rearViewDownState;
	controls [0].firePrimaryDownCount += m_info->firePrimaryDownCount;
	controls [0].firePrimaryState |= m_info->firePrimaryState;
	controls [0].fireSecondaryState |= m_info->fireSecondaryState;
	controls [0].fireSecondaryDownCount += m_info->fireSecondaryDownCount;
	controls [0].fireFlareDownCount += m_info->fireFlareDownCount;
	controls [0].dropBombDownCount += m_info->dropBombDownCount;
	controls [0].automapDownCount += m_info->automapDownCount;
	controls [0].automapState |= m_info->automapState;

   if (m_version>=3)
	 {
		ubyte *temp_ptr = reinterpret_cast<ubyte*> (m_info);
		temp_ptr += (sizeof (ext_control_info) + sizeof (CAngleVector) + 64 + sizeof (CFixVector) + sizeof (CFixMatrix));

	   if (* (temp_ptr))
		 controls [0].cyclePrimaryCount= (* (temp_ptr));
	   if (* (temp_ptr+1))
		 controls [0].cycleSecondaryCount= (* (temp_ptr+1));

		if (* (temp_ptr+2))
		 controls [0].afterburnerState= (* (temp_ptr+2));
		if (* (temp_ptr+3))
		 controls [0].headlightCount= (* (temp_ptr+3));
  	 }
   if (m_version>=4)
	 {
	  advanced_ext_control_info *temp_ptr = reinterpret_cast<advanced_ext_control_info*> (m_info);

     if (temp_ptr->Reactor_blown)
      {
       if (gameData.app.nGameMode & GM_MULTI)
		    NetDestroyReactor (ObjFindFirstOfType (OBJ_REACTOR));
		 else
			 DoReactorDestroyedStuff (ObjFindFirstOfType (OBJ_REACTOR));
	   }
	}
}

//------------------------------------------------------------------------------

void CExternalControls::Destroy (void)
{
if (m_name) {
	delete[] m_name;
	m_name = NULL;
	}
}

//------------------------------------------------------------------------------

void KCSetControls (int bGet)
{
	int i, j;

controls.SetType ();
return;
for (i = 0, j = NUM_KEY_CONTROLS; i < j; i++) {
	if (bGet)
		controlSettings.custom [0][i] = kcKeyboard [i].value;
	else
		kcKeyboard [i].value = controlSettings.custom [0][i];
	}
//if ((gameConfig.nControlType > 0) && (gameConfig.nControlType < 5)) {
if (gameOpts->input.joystick.bUse) {
	for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++) {
		if (bGet)
			controlSettings.custom [gameStates.input.nJoyType][i] = kcJoystick [i].value;
		else {
			kcJoystick [i].value = controlSettings.custom [gameStates.input.nJoyType][i];
			if (kcJoystick [i].nType == BT_INVERT) {
				if (kcJoystick [i].value != 1)
					kcJoystick [i].value = 0;
				controlSettings.custom [gameStates.input.nJoyType][i] = kcJoystick [i].value;
				}
			}
		}
	}
//else if (gameConfig.nControlType > 4 && gameConfig.nControlType < CONTROL_WINJOYSTICK) {
if (gameOpts->input.mouse.bUse) {
	for (i = 0, j = NUM_MOUSE_CONTROLS; i < j; i++) {
		if (bGet)
			controlSettings.custom [gameStates.input.nMouseType][i] = kcMouse [i].value;
		else {
			kcMouse [i].value = controlSettings.custom [gameStates.input.nMouseType][i];
			if (kcMouse [i].nType == BT_INVERT) {
				if (kcMouse [i].value != 1)
					kcMouse [i].value = 0;
				controlSettings.custom [gameStates.input.nMouseType][i] = kcMouse [i].value;
				}
			}
		}
	}
//else
if (gameConfig.nControlType == CONTROL_WINJOYSTICK) {
	for (i = 0, j = NUM_JOY_CONTROLS; i < j; i++) {
		if (bGet)
			controlSettings.custom [gameConfig.nControlType][i] = kcSuperJoy [i].value;
		else {
			kcSuperJoy [i].value = controlSettings.custom [gameConfig.nControlType][i];
			if (kcSuperJoy [i].nType == BT_INVERT) {
				if (kcSuperJoy [i].value!=1)
					kcSuperJoy [i].value	= 0;
				controlSettings.custom [gameConfig.nControlType][i] = kcSuperJoy [i].value;
				}
			}
		}
	}
for (i = 0, j = NUM_HOTKEY_CONTROLS; i < j; i++) {
	if (bGet)
		controlSettings.d2xCustom [i] = kcHotkeys [i].value;
	else
		kcHotkeys [i].value = controlSettings.d2xCustom [i];
	}
for (i = 0; i < 4; i++)
	JoySetDeadzone (gameOpts->input.joystick.deadzones [i], i);
}

//------------------------------------------------------------------------------

int KcKeyboardSize (void) {return sizeofa (kcKeyboard);}
int KcMouseSize (void) {return sizeofa (kcMouse);}
int KcJoystickSize (void) {return sizeofa (kcJoystick);}
int KcSuperJoySize (void) {return sizeofa (kcSuperJoy);}
int KcHotkeySize (void) {return sizeofa (kcHotkeys);}

//------------------------------------------------------------------------------
//eof
