/* zlib/libpng license below:
Copyright (c) 2004-2009 Pierre-Michel Ricordel (pricorde{AT}rigsofrods{DOT}com), Thomas Fischer (thomas{AT}rigsofrods{DOT}com)

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

    1. The origin of this software must not be misrepresented; you must not
    claim that you wrote the original software. If you use this software
    in a product, an acknowledgment in the product documentation would be
    appreciated but is not required.

    2. Altered source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

    3. This notice may not be removed or altered from any source
    distribution.
*/
#include "InputEngine.h"

#include <Ogre.h>
#include <OgreStringConverter.h>
#include <OgreException.h>
#include <OgreWindowEventUtilities.h>
#include "Settings.h"

#ifndef NOOGRE
#include "IngameConsole.h"
#include "gui_manager.h"
#include "language.h"
#else
#define _L(x) x
#endif

const char *mOISDeviceType[6] = {"Unknown Device", "Keyboard", "Mouse", "JoyStick", "Tablet", "Other Device"};

// LOOOONG list of possible events. see the struct type for the structure ;)
eventInfo_t eventInfo[] = {
	{
		"AIRPLANE_STEER_RIGHT",
		EV_AIRPLANE_STEER_RIGHT,
		"Keyboard RIGHT",
		_L("steer right")
	},
	{
		"AIRPLANE_BRAKE",
		EV_AIRPLANE_BRAKE,
		"Keyboard B",
		_L("normal brake for an aircraft")
	},
	{
		"AIRPLANE_ELEVATOR_DOWN",
		EV_AIRPLANE_ELEVATOR_DOWN,
		"Keyboard DOWN",
		_L("pull the elevator down in an aircraft.")
	},
	{
		"AIRPLANE_ELEVATOR_UP",
		EV_AIRPLANE_ELEVATOR_UP,
		"Keyboard UP",
		_L("pull the elevator up in an aircraft.")
	},
	{
		"AIRPLANE_FLAPS_FULL",
		EV_AIRPLANE_FLAPS_FULL,
		"Keyboard CTRL+2",
		_L("full flaps in an aircraft.")
	},
	{
		"AIRPLANE_FLAPS_LESS",
		EV_AIRPLANE_FLAPS_LESS,
		"Keyboard EXPL+1",
		_L("one step less flaps.")
	},
	{
		"AIRPLANE_FLAPS_MORE",
		EV_AIRPLANE_FLAPS_MORE,
		"Keyboard EXPL+2",
		_L("one step more flaps.")
	},
	{
		"AIRPLANE_FLAPS_NONE",
		EV_AIRPLANE_FLAPS_NONE,
		"Keyboard CTRL+1",
		_L("no flaps.")
	},
	{
		"AIRPLANE_PARKING_BRAKE",
		EV_AIRPLANE_PARKING_BRAKE,
		"Keyboard P",
		_L("airplane parking brake.")

	},
	{
		"AIRPLANE_REVERSE",
		EV_AIRPLANE_REVERSE,
		"Keyboard R",
		_L("reverse the turboprops")
	},
	{
		"AIRPLANE_RUDDER_LEFT",
		EV_AIRPLANE_RUDDER_LEFT,
		"Keyboard Z",
		_L("rudder left")
	},
	{
		"AIRPLANE_RUDDER_RIGHT",
		EV_AIRPLANE_RUDDER_RIGHT,
		"Keyboard X",
		_L("rudder right")
	},
	{
		"AIRPLANE_STEER_LEFT",
		EV_AIRPLANE_STEER_LEFT,
		"Keyboard LEFT",
		_L("steer left")
	},
	{
		"AIRPLANE_STEER_RIGHT",
		EV_AIRPLANE_STEER_RIGHT,
		"Keyboard RIGHT",
		_L("steer right")
	},
	{
		"AIRPLANE_THROTTLE_AXIS",
		EV_AIRPLANE_THROTTLE_AXIS,
		"None",
		_L("throttle axis. Only use this if you have fitting hardware :) (i.e. a Slider)")
	},
	{
		"AIRPLANE_THROTTLE_DOWN",
		EV_AIRPLANE_THROTTLE_DOWN,
		"Keyboard EXPL+PGDOWN",
		_L("decreases the airplane thrust")
	},
	{
		"AIRPLANE_THROTTLE_FULL",
		EV_AIRPLANE_THROTTLE_FULL,
		"Keyboard CTRL+PGUP",
		_L("full thrust")
	},
	{
		"AIRPLANE_THROTTLE_NO",
		EV_AIRPLANE_THROTTLE_NO,
		"Keyboard CTRL+PGDOWN",
		_L("no thrust")
	},
	{
		"AIRPLANE_THROTTLE_UP",
		EV_AIRPLANE_THROTTLE_UP,
		"Keyboard EXPL+PGUP",
		_L("increase the airplane thrust")
	},
	{
		"AIRPLANE_TOGGLE_ENGINES",
		EV_AIRPLANE_TOGGLE_ENGINES,
		"Keyboard CTRL+HOME",
		_L("switch all engines on / off")
	},
	{
		"BOAT_CENTER_RUDDER",
		EV_BOAT_CENTER_RUDDER,
		"Keyboard DOWN",
		_L("center the rudder")
	},
	{
		"BOAT_REVERSE",
		EV_BOAT_REVERSE,
		"Keyboard UP",
		_L("no thrust")
	},
	{
		"BOAT_STEER_LEFT",
		EV_BOAT_STEER_LEFT,
		"Keyboard LEFT",
		_L("steer left a step")
	},
	{
		"BOAT_STEER_LEFT_AXIS",
		EV_BOAT_STEER_LEFT_AXIS,
		"None",
		_L("steer left (analog value!)")
	},
	{
		"BOAT_STEER_RIGHT",
		EV_BOAT_STEER_RIGHT,
		"Keyboard RIGHT",
		_L("steer right a step")
	},
	{
		"BOAT_STEER_RIGHT_AXIS",
		EV_BOAT_STEER_RIGHT_AXIS,
		"None",
		_L("steer right (analog value!)")
	},
	{
		"BOAT_THROTTLE_AXIS",
		EV_BOAT_THROTTLE_AXIS,
		"None",
		_L("throttle axis. Only use this if you have fitting hardware :) (i.e. a Slider)")
	},
	{
		"BOAT_THROTTLE_DOWN",
		EV_BOAT_THROTTLE_DOWN,
		"Keyboard PGDOWN",
		_L("decrease throttle")
	},
	{
		"BOAT_THROTTLE_UP",
		EV_BOAT_THROTTLE_UP,
		"Keyboard PGUP",
		_L("increase throttle")
	},
	{
		"CAELUM_DECREASE_TIME",
		EV_CAELUM_DECREASE_TIME,
		"Keyboard EXPL+SUBTRACT",
		_L("decrease day-time")
	},
	{
		"CAELUM_DECREASE_TIME_FAST",
		EV_CAELUM_DECREASE_TIME_FAST,
		"Keyboard SHIFT+SUBTRACT",
		_L("decrease day-time a lot faster")
	},
	{
		"CAELUM_INCREASE_TIME",
		EV_CAELUM_INCREASE_TIME,
		"Keyboard EXPL+ADD",
		_L("increase day-time")
	},
	{
		"CAELUM_INCREASE_TIME_FAST",
		EV_CAELUM_INCREASE_TIME_FAST,
		"Keyboard SHIFT+ADD",
		_L("increase day-time a lot faster")
	},
	{
		"CAMERA_CHANGE",
		EV_CAMERA_CHANGE,
		"Keyboard EXPL+C",
		_L("change camera mode")
	},
	{
		"CAMERA_LOOKBACK",
		EV_CAMERA_LOOKBACK,
		"Keyboard NUMPAD1",
		_L("look back (toggles between normal and lookback)")
	},
	{
		"CAMERA_RESET",
		EV_CAMERA_RESET,
		"Keyboard NUMPAD5",
		_L("reset the camera position")
	},
	{
		"CAMERA_ROTATE_DOWN",
		EV_CAMERA_ROTATE_DOWN,
		"Keyboard NUMPAD2",
		_L("rotate camera down")
	},
	{
		"CAMERA_ROTATE_LEFT",
		EV_CAMERA_ROTATE_LEFT,
		"Keyboard NUMPAD4",
		_L("rotate camera left")
	},
	{
		"CAMERA_ROTATE_RIGHT",
		EV_CAMERA_ROTATE_RIGHT,
		"Keyboard NUMPAD6",
		_L("rotate camera right")
	},
	{
		"CAMERA_ROTATE_UP",
		EV_CAMERA_ROTATE_UP,
		"Keyboard NUMPAD8",
		_L("rotate camera up")
	},
	{
		"CAMERA_ZOOM_IN",
		EV_CAMERA_ZOOM_IN,
		"Keyboard EXPL+NUMPAD9",
		_L("zoom camera in")
	},
	{
		"CAMERA_ZOOM_IN_FAST",
		EV_CAMERA_ZOOM_IN_FAST,
		"Keyboard SHIFT+NUMPAD9",
		_L("zoom camera in faster")
	},
	{
		"CAMERA_ZOOM_OUT",
		EV_CAMERA_ZOOM_OUT,
		"Keyboard EXPL+NUMPAD3",
		_L("zoom camera out")
	},
	{
		"CAMERA_ZOOM_OUT_FAST",
		EV_CAMERA_ZOOM_OUT_FAST,
		"Keyboard SHIFT+NUMPAD3",
		_L("zoom camera out faster")
	},
	{
		"CHARACTER_BACKWARDS",
		EV_CHARACTER_BACKWARDS,
		"Keyboard S",
		_L("step backwards with the character")
	},
	{
		"CHARACTER_FORWARD",
		EV_CHARACTER_FORWARD,
		"Keyboard W",
		_L("step forward with the character")
	},
	{
		"CHARACTER_JUMP",
		EV_CHARACTER_JUMP,
		"Keyboard SPACE",
		_L("let the character jump")
	},
	{
		"CHARACTER_LEFT",
		EV_CHARACTER_LEFT,
		"Keyboard LEFT",
		_L("rotate character left")
	},
	{
		"CHARACTER_RIGHT",
		EV_CHARACTER_RIGHT,
		"Keyboard RIGHT",
		_L("rotate character right")
	},
	{
		"CHARACTER_RUN",
		EV_CHARACTER_RUN,
		"Keyboard SHIFT+W",
		_L("let the character run")
	},
	{
		"CHARACTER_SIDESTEP_LEFT",
		EV_CHARACTER_SIDESTEP_LEFT,
		"Keyboard A",
		_L("sidestep to the left")
	},
	{
		"CHARACTER_SIDESTEP_RIGHT",
		EV_CHARACTER_SIDESTEP_RIGHT,
		"Keyboard D",
		_L("sidestep to the right")
	},
	{
		"COMMANDS_01",
		EV_COMMANDS_01,
		"Keyboard EXPL+F1",
		_L("Command 1")
	},
	{
		"COMMANDS_02",
		EV_COMMANDS_02,
		"Keyboard EXPL+F2",
		_L("Command 2")
	},
	{
		"COMMANDS_03",
		EV_COMMANDS_03,
		"Keyboard EXPL+F3",
		_L("Command 3")
	},
	{
		"COMMANDS_04",
		EV_COMMANDS_04,
		"Keyboard EXPL+F4",
		_L("Command 4")
	},
	{
		"COMMANDS_05",
		EV_COMMANDS_05,
		"Keyboard EXPL+F5",
		_L("Command 5")
	},
	{
		"COMMANDS_06",
		EV_COMMANDS_06,
		"Keyboard EXPL+F6",
		_L("Command 6")
	},
	{
		"COMMANDS_07",
		EV_COMMANDS_07,
		"Keyboard EXPL+F7",
		_L("Command 7")
	},
	{
		"COMMANDS_08",
		EV_COMMANDS_08,
		"Keyboard EXPL+F8",
		_L("Command 8")
	},
	{
		"COMMANDS_09",
		EV_COMMANDS_09,
		"Keyboard EXPL+F9",
		_L("Command 9")
	},
	{
		"COMMANDS_10",
		EV_COMMANDS_10,
		"Keyboard EXPL+F10",
		_L("Command 10")
	},
	{
		"COMMANDS_11",
		EV_COMMANDS_11,
		"Keyboard EXPL+F11",
		_L("Command 11")
	},
	{
		"COMMANDS_12",
		EV_COMMANDS_12,
		"Keyboard EXPL+F12",
		_L("Command 12")
	},
	{
		"COMMANDS_13",
		EV_COMMANDS_13,
		"",
		_L("Command 13")
	},
	{
		"COMMANDS_14",
		EV_COMMANDS_14,
		"",
		_L("Command 14")
	},
	{
		"COMMANDS_15",
		EV_COMMANDS_15,
		"",
		_L("Command 15")
	},
	{
		"COMMANDS_16",
		EV_COMMANDS_16,
		"",
		_L("Command 16")
	},
	{
		"COMMANDS_17",
		EV_COMMANDS_17,
		"",
		_L("Command 17")
	},
	{
		"COMMANDS_18",
		EV_COMMANDS_18,
		"",
		_L("Command 18")
	},
	{
		"COMMANDS_19",
		EV_COMMANDS_19,
		"",
		_L("Command 19")
	},
	{
		"COMMANDS_20",
		EV_COMMANDS_20,
		"",
		_L("Command 20")
	},
	{
		"COMMANDS_21",
		EV_COMMANDS_21,
		"",
		_L("Command 21")
	},
	{
		"COMMANDS_22",
		EV_COMMANDS_22,
		"",
		_L("Command 22")
	},
	{
		"COMMANDS_23",
		EV_COMMANDS_23,
		"",
		_L("Command 23")
	},
	{
		"COMMANDS_24",
		EV_COMMANDS_24,
		"",
		_L("Command 24")
	},
	{
		"COMMANDS_25",
		EV_COMMANDS_25,
		"",
		_L("Command 25")
	},
	{
		"COMMANDS_26",
		EV_COMMANDS_26,
		"",
		_L("Command 26")
	},
	{
		"COMMANDS_27",
		EV_COMMANDS_27,
		"",
		_L("Command 27")
	},
	{
		"COMMANDS_28",
		EV_COMMANDS_28,
		"",
		_L("Command 28")
	},
	{
		"COMMANDS_29",
		EV_COMMANDS_29,
		"",
		_L("Command 29")
	},
	{
		"COMMANDS_30",
		EV_COMMANDS_30,
		"",
		_L("Command 30")
	},
	{
		"COMMANDS_31",
		EV_COMMANDS_31,
		"",
		_L("Command 31")
	},
	{
		"COMMANDS_32",
		EV_COMMANDS_32,
		"",
		_L("Command 32")
	},
	{
		"COMMANDS_33",
		EV_COMMANDS_33,
		"",
		_L("Command 33")
	},
	{
		"COMMANDS_34",
		EV_COMMANDS_34,
		"",
		_L("Command 34")
	},
	{
		"COMMANDS_35",
		EV_COMMANDS_35,
		"",
		_L("Command 35")
	},
	{
		"COMMANDS_36",
		EV_COMMANDS_36,
		"",
		_L("Command 36")
	},
	{
		"COMMANDS_37",
		EV_COMMANDS_37,
		"",
		_L("Command 37")
	},
	{
		"COMMANDS_38",
		EV_COMMANDS_38,
		"",
		_L("Command 38")
	},
	{
		"COMMANDS_39",
		EV_COMMANDS_39,
		"",
		_L("Command 39")
	},
	{
		"COMMANDS_40",
		EV_COMMANDS_40,
		"",
		_L("Command 40")
	},
	{
		"COMMANDS_41",
		EV_COMMANDS_41,
		"",
		_L("Command 41")
	},
	{
		"COMMANDS_42",
		EV_COMMANDS_42,
		"",
		_L("Command 42")
	},
	{
		"COMMANDS_43",
		EV_COMMANDS_43,
		"",
		_L("Command 43")
	},
	{
		"COMMANDS_44",
		EV_COMMANDS_44,
		"",
		_L("Command 44")
	},
	{
		"COMMANDS_45",
		EV_COMMANDS_45,
		"",
		_L("Command 45")
	},
	{
		"COMMANDS_46",
		EV_COMMANDS_46,
		"",
		_L("Command 46")
	},
	{
		"COMMANDS_47",
		EV_COMMANDS_47,
		"",
		_L("Command 47")
	},
	{
		"COMMANDS_48",
		EV_COMMANDS_48,
		"",
		_L("Command 48")
	},
	{
		"COMMON_CONSOLEDISPLAY",
		EV_COMMON_CONSOLEDISPLAY,
		"",
		_L("show / hide the console")
	},
	{
		"COMMON_CONSOLEMODE",
		EV_COMMON_CONSOLEMODE,
		"",
		_L("toggle appearance of console")
	},
	{
		"COMMON_ENTER_CHAT",
		EV_COMMON_ENTER_CHAT,
		"",
		_L("enter the chat")
	},
	{
		"COMMON_ENTER_OR_EXIT_TRUCK",
		EV_COMMON_ENTER_OR_EXIT_TRUCK,
		"",
		_L("enter or exit a truck")
	},
	{
		"COMMON_HIDE_GUI",
		EV_COMMON_HIDE_GUI,
		"",
		_L("hide all GUI elements")
	},
	{
		"COMMON_LOCK",
		EV_COMMON_LOCK,
		"",
		_L("connect hook node to a node in close proximity")
	},
	{
		"COMMON_MAP_ALPHA",
		EV_COMMON_MAP_ALPHA,
		"",
		_L("toggle translucency of overview-map")
	},
	{
		"COMMON_OUTPUT_POSITION",
		EV_COMMON_OUTPUT_POSITION,
		"",
		_L("write current position to log (you can open the logfile and reuse the position)")
	},
	{
		"COMMON_PRESSURE_LESS",
		EV_COMMON_PRESSURE_LESS,
		"",
		_L("decrease tire pressure (note: only very few trucks support this)")
	},
	{
		"COMMON_PRESSURE_MORE",
		EV_COMMON_PRESSURE_MORE,
		"",
		_L("increase tire pressure (note: only very few trucks support this)")
	},
	{
		"COMMON_QUIT_GAME",
		EV_COMMON_QUIT_GAME,
		"",
		_L("exit the game")
	},
	{
		"COMMON_RESCUE_TRUCK",
		EV_COMMON_RESCUE_TRUCK,
		"",
		_L("teleport to rescue truck")
	},
	{
		"COMMON_RESET_TRUCK",
		EV_COMMON_RESET_TRUCK,
		"",
		_L("reset truck to original starting position")
	},
	{
		"COMMON_SCREENSHOT",
		EV_COMMON_SCREENSHOT,
		"",
		_L("take a screenshot")
	},
	{
		"COMMON_SECURE_LOAD",
		EV_COMMON_SECURE_LOAD,
		"",
		_L("tie a load to the truck")
	},
	{
		"COMMON_SHOW_SKELETON",
		EV_COMMON_SHOW_SKELETON,
		"",
		_L("toggle skeleton display mode")
	},
	{
		"COMMON_START_TRUCK_EDITOR",
		EV_COMMON_START_TRUCK_EDITOR,
		"",
		_L("start the old truck editor")
	},
	{
		"COMMON_TOGGLE_CUSTOM_PARTICLES",
		EV_COMMON_TOGGLE_CUSTOM_PARTICLES,
		"",
		_L("toggle particle cannon")
	},
	{
		"COMMON_TOGGLE_MAT_DEBUG",
		EV_COMMON_TOGGLE_MAT_DEBUG,
		"",
		_L("debug purpose - dont use")
	},
	{
		"COMMON_TOGGLE_RENDER_MODE",
		EV_COMMON_TOGGLE_RENDER_MODE,
		"",
		_L("toggle render mode (solid, wireframe and points)")
	},
	{
		"COMMON_TOGGLE_REPLAY_MODE",
		EV_COMMON_TOGGLE_REPLAY_MODE,
		"",
		_L("enable or disable replay mode")
	},
	{
		"COMMON_TOGGLE_STATS",
		EV_COMMON_TOGGLE_STATS,
		"",
		_L("toggle Ogre statistics (FPS etc.)")
	},
	{
		"COMMON_TOGGLE_TRUCK_BEACONS",
		EV_COMMON_TOGGLE_TRUCK_BEACONS,
		"",
		_L("toggle truck beacons")
	},
	{
		"COMMON_TOGGLE_TRUCK_LIGHTS",
		EV_COMMON_TOGGLE_TRUCK_LIGHTS,
		"",
		_L("toggle truck front lights")
	},
	{
		"COMMON_TRUCK_INFO",
		EV_COMMON_TRUCK_INFO,
		"",
		_L("toggle truck HUD")
	},
	{
		"COMMON_VIEW_MAP",
		EV_COMMON_VIEW_MAP,
		"",
		_L("toggle map modes")
	},
	{
		"COMMON_FOV_LESS",
		EV_COMMON_FOV_LESS,
		"",
		_L("decreases the current FOV value")
	},
	{
		"COMMON_FOV_MORE",
		EV_COMMON_FOV_MORE,
		"",
		_L("increase the current FOV value")
	},
	{
		"GRASS_LESS",
		EV_GRASS_LESS,
		"",
		_L("EXPERIMENTAL: remove some grass")
	},
	{
		"GRASS_MORE",
		EV_GRASS_MORE,
		"",
		_L("EXPERIMENTAL: add some grass")
	},
	{
		"GRASS_MOST",
		EV_GRASS_MOST,
		"",
		_L("EXPERIMENTAL: set maximum amount of grass")
	},
	{
		"GRASS_NONE",
		EV_GRASS_NONE,
		"",
		_L("EXPERIMENTAL: remove grass completely")
	},
	{
		"GRASS_SAVE",
		EV_GRASS_SAVE,
		"",
		_L("EXPERIMENTAL: save changes to the grass density image")
	},
	{
		"MAP_IN",
		EV_MAP_IN,
		"",
		_L("zoom into the overview map in interactive mode")
	},
	{
		"MAP_INTERACTIVE_TOGGLE",
		EV_MAP_INTERACTIVE_TOGGLE,
		"",
		_L("toggle overview map interactive mode")
	},
	{
		"MAP_OUT",
		EV_MAP_OUT,
		"",
		_L("zoom into the overview map in interactive mode")
	},
	{
		"MENU_DOWN",
		EV_MENU_DOWN,
		"",
		_L("select next element in current category")
	},
	{
		"MENU_LEFT",
		EV_MENU_LEFT,
		"",
		_L("select previous category")
	},
	{
		"MENU_RIGHT",
		EV_MENU_RIGHT,
		"",
		_L("select next category")
	},
	{
		"MENU_SELECT",
		EV_MENU_SELECT,
		"",
		_L("select focussed item and close menu")
	},
	{
		"MENU_UP",
		EV_MENU_UP,
		"",
		_L("select previous element in current category")
	},
	{
		"TERRAINEDITOR_BUILT",
		EV_TERRAINEDITOR_BUILT,
		"",
		_L("place currently selected object at current position")
	},
	{
		"TERRAINEDITOR_PITCHBACKWARD",
		EV_TERRAINEDITOR_PITCHBACKWARD,
		"",
		_L("pitch object backward")
	},
	{
		"TERRAINEDITOR_PITCHFOREWARD",
		EV_TERRAINEDITOR_PITCHFOREWARD,
		"",
		_L("pitch object foreward")
	},
	{
		"TERRAINEDITOR_ROTATELEFT",
		EV_TERRAINEDITOR_ROTATELEFT,
		"",
		_L("rotate object left")
	},
	{
		"TERRAINEDITOR_ROTATERIGHT",
		EV_TERRAINEDITOR_ROTATERIGHT,
		"",
		_L("rotate object right")
	},
	{
		"TERRAINEDITOR_SELECTROAD",
		EV_TERRAINEDITOR_SELECTROAD,
		"",
		_L("switch to road laying mode")
	},
	{
		"TERRAINEDITOR_TOGGLEOBJECT",
		EV_TERRAINEDITOR_TOGGLEOBJECT,
		"",
		_L("toggle between available objects")
	},
	{
		"TERRAINEDITOR_TOGGLEROADTYPE",
		EV_TERRAINEDITOR_TOGGLEROADTYPE,
		"",
		_L("toggle between available road types")
	},
	{
		"TRUCK_ACCELERATE",
		EV_TRUCK_ACCELERATE,
		"",
		_L("accelerate the truck")
	},
	{
		"TRUCK_AUTOSHIFT_DOWN",
		EV_TRUCK_AUTOSHIFT_DOWN,
		"",
		_L("shift automatic transmission one gear down")
	},
	{
		"TRUCK_AUTOSHIFT_UP",
		EV_TRUCK_AUTOSHIFT_UP,
		"",
		_L("shift automatic transmission one gear up")
	},
	{
		"TRUCK_BLINK_LEFT",
		EV_TRUCK_BLINK_LEFT,
		"",
		_L("toggle left direction indicator (blinker)")
	},
	{
		"TRUCK_BLINK_RIGHT",
		EV_TRUCK_BLINK_RIGHT,
		"",
		_L("toggle right direction indicator (blinker)")
	},
	{
		"TRUCK_BLINK_WARN",
		EV_TRUCK_BLINK_WARN,
		"",
		_L("toggle all direction indicators")
	},
	{
		"TRUCK_BRAKE",
		EV_TRUCK_BRAKE,
		"",
		_L("brake")
	},
	{
		"TRUCK_HORN",
		EV_TRUCK_HORN,
		"",
		_L("truck horn")
	},
	{
		"TRUCK_LIGHTTOGGLE1",
		EV_TRUCK_LIGHTTOGGLE1,
		"",
		_L("toggle custom light 1")
	},
	{
		"TRUCK_LIGHTTOGGLE10",
		EV_TRUCK_LIGHTTOGGLE10,
		"",
		_L("toggle custom light 10")
	},
	{
		"TRUCK_LIGHTTOGGLE2",
		EV_TRUCK_LIGHTTOGGLE2,
		"",
		_L("toggle custom light 2")
	},
	{
		"TRUCK_LIGHTTOGGLE3",
		EV_TRUCK_LIGHTTOGGLE3,
		"",
		_L("toggle custom light 3")
	},
	{
		"TRUCK_LIGHTTOGGLE4",
		EV_TRUCK_LIGHTTOGGLE4,
		"",
		_L("toggle custom light 4")
	},
	{
		"TRUCK_LIGHTTOGGLE5",
		EV_TRUCK_LIGHTTOGGLE5,
		"",
		_L("toggle custom light 5")
	},
	{
		"TRUCK_LIGHTTOGGLE6",
		EV_TRUCK_LIGHTTOGGLE6,
		"",
		_L("toggle custom light 6")
	},
	{
		"TRUCK_LIGHTTOGGLE7",
		EV_TRUCK_LIGHTTOGGLE7,
		"",
		_L("toggle custom light 7")
	},
	{
		"TRUCK_LIGHTTOGGLE8",
		EV_TRUCK_LIGHTTOGGLE8,
		"",
		_L("toggle custom light 8")
	},
	{
		"TRUCK_LIGHTTOGGLE9",
		EV_TRUCK_LIGHTTOGGLE9,
		"",
		_L("toggle custom light 9")
	},
	{
		"TRUCK_MANUAL_CLUTCH",
		EV_TRUCK_MANUAL_CLUTCH,
		"",
		_L("manual clutch (for manual transmission)")
	},
	{
		"TRUCK_PARKING_BRAKE",
		EV_TRUCK_PARKING_BRAKE,
		"",
		_L("toggle parking brake")
	},
	{
		"TRUCK_SHIFT_DOWN",
		EV_TRUCK_SHIFT_DOWN,
		"",
		_L("shift one gear down in manual transmission mode")
	},
	{
		"TRUCK_SHIFT_NEUTRAL",
		EV_TRUCK_SHIFT_NEUTRAL,
		"",
		_L("shift to neutral gear in manual transmission mode")
	},
	{
		"TRUCK_SHIFT_UP",
		EV_TRUCK_SHIFT_UP,
		"",
		_L("shift one gear up in manual transmission mode")
	},
	{
		"TRUCK_SHIFT_GEAR_REVERSE",
		EV_TRUCK_SHIFT_GEAR_REVERSE,
		"",
		_L("shift directly to reverse gear")
	},
	{
		"TRUCK_SHIFT_GEAR1",
		EV_TRUCK_SHIFT_GEAR1,
		"",
		_L("shift directly to first gear")
	},
	{
		"TRUCK_SHIFT_GEAR2",
		EV_TRUCK_SHIFT_GEAR2,
		"",
		_L("shift directly to second gear")
	},
	{
		"TRUCK_SHIFT_GEAR3",
		EV_TRUCK_SHIFT_GEAR3,
		"",
		_L("shift directly to third gear")
	},
	{
		"TRUCK_SHIFT_GEAR4",
		EV_TRUCK_SHIFT_GEAR4,
		"",
		_L("shift directly to fourth gear")
	},
	{
		"TRUCK_SHIFT_GEAR5",
		EV_TRUCK_SHIFT_GEAR5,
		"",
		_L("shift directly to 5th gear")
	},
	{
		"TRUCK_SHIFT_GEAR6",
		EV_TRUCK_SHIFT_GEAR6,
		"",
		_L("shift directly to 6th gear")
	},
	{
		"TRUCK_SHIFT_GEAR7",
		EV_TRUCK_SHIFT_GEAR7,
		"",
		_L("shift directly to 7th gear")
	},
	{
		"TRUCK_SHIFT_GEAR8",
		EV_TRUCK_SHIFT_GEAR8,
		"",
		_L("shift directly to 8th gear")
	},
	{
		"TRUCK_SHIFT_GEAR9",
		EV_TRUCK_SHIFT_GEAR9,
		"",
		_L("shift directly to 9th gear")
	},
	{
		"TRUCK_SHIFT_GEAR10",
		EV_TRUCK_SHIFT_GEAR10,
		"",
		_L("shift directly to 10th gear")
	},
	{
		"TRUCK_SHIFT_GEAR11",
		EV_TRUCK_SHIFT_GEAR11,
		"",
		_L("shift directly to 11th gear")
	},
	{
		"TRUCK_SHIFT_GEAR12",
		EV_TRUCK_SHIFT_GEAR12,
		"",
		_L("shift directly to 12th gear")
	},
	
	{
		"TRUCK_SHIFT_GEAR13",
		EV_TRUCK_SHIFT_GEAR13,
		"",
		_L("shift directly to 13th gear")
	},
	{
		"TRUCK_SHIFT_GEAR14",
		EV_TRUCK_SHIFT_GEAR14,
		"",
		_L("shift directly to 14th gear")
	},
	{
		"TRUCK_SHIFT_GEAR15",
		EV_TRUCK_SHIFT_GEAR15,
		"",
		_L("shift directly to 15th gear")
	},
	{
		"TRUCK_SHIFT_GEAR16",
		EV_TRUCK_SHIFT_GEAR16,
		"",
		_L("shift directly to 16th gear")
	},
	{
		"TRUCK_SHIFT_GEAR17",
		EV_TRUCK_SHIFT_GEAR17,
		"",
		_L("shift directly to 17th gear")
	},
	{
		"TRUCK_SHIFT_GEAR18",
		EV_TRUCK_SHIFT_GEAR18,
		"",
		_L("shift directly to 18th gear")
	},
	{
		"TRUCK_SHIFT_LOWRANGE",
		EV_TRUCK_SHIFT_LOWRANGE,
		"",
		_L("sets low range (1-6) for H-shaft")
	},
	{
		"TRUCK_SHIFT_MIDRANGE",
		EV_TRUCK_SHIFT_MIDRANGE,
		"",
		_L("sets middle range (7-12) for H-shaft")
	},
	{
		"TRUCK_SHIFT_HIGHRANGE",
		EV_TRUCK_SHIFT_HIGHRANGE,
		"",
		_L("sets high range (13-18) for H-shaft")
	},
	{
		"TRUCK_STARTER",
		EV_TRUCK_STARTER,
		"",
		_L("hold to start the engine")
	},
	{
		"TRUCK_STEER_LEFT",
		EV_TRUCK_STEER_LEFT,
		"",
		_L("steer left")
	},
	{
		"TRUCK_STEER_RIGHT",
		EV_TRUCK_STEER_RIGHT,
		"",
		_L("steer right")
	},
	{
		"TRUCK_SWITCH_SHIFT_MODES",
		EV_TRUCK_SWITCH_SHIFT_MODES,
		"",
		_L("toggle between transmission modes")
	},
	{
		"TRUCK_TOGGLE_AXLE_LOCK",
		EV_TRUCK_TOGGLE_AXLE_LOCK,
		"",
		_L("Cycle between available differental models")
	},
	{
		"TRUCK_TOGGLE_CONTACT",
		EV_TRUCK_TOGGLE_CONTACT,
		"",
		_L("toggle ignition")
	},

	// "new" commands
	{
		"COMMON_SHOWTRUCKTOOL",
		EV_COMMON_SHOWTRUCKTOOL,
		"",
		_L("show truck tool")
	},
	{
		"COMMON_RELOAD_ROADS",
		EV_COMMON_RELOAD_ROADS,
		"",
		_L("reloads the roads (experimental)")
	},
	{
		"COMMON_FULLSCREEN_TOGGLE",
		EV_COMMON_FULLSCREEN_TOGGLE,
		"",
		_L("toggle between windowed and fullscreen mode")
	},
	{
		"CAMERA_FREE_MODE_FIX",
		EV_CAMERA_FREE_MODE_FIX,
		"",
		_L("fix the camera to a position")
	},
	{
		"CAMERA_FREE_MODE",
		EV_CAMERA_FREE_MODE,
		"",
		_L("enable / disable free camera mode")
	},
	{
		"TRUCK_LEFT_MIRROR_LEFT",
		EV_TRUCK_LEFT_MIRROR_LEFT,
		"",
		_L("move left mirror to the left")
	},
	{
		"TRUCK_LEFT_MIRROR_RIGHT",
		EV_TRUCK_LEFT_MIRROR_RIGHT,
		"",
		_L("move left mirror to the right")
	},
	{
		"TRUCK_RIGHT_MIRROR_LEFT",
		EV_TRUCK_RIGHT_MIRROR_LEFT,
		"",
		_L("more right mirror to the left")
	},
	{
		"TRUCK_RIGHT_MIRROR_RIGHT",
		EV_TRUCK_RIGHT_MIRROR_RIGHT,
		"",
		_L("move right mirror to the right")
	},
	{
		"COMMON_REPLAY_FORWARD",
		EV_COMMON_REPLAY_FORWARD,
		"",
		_L("more replay forward")
	},
	{
		"COMMON_REPLAY_BACKWARD",
		EV_COMMON_REPLAY_BACKWARD,
		"",
		_L("more replay backward")
	},
	{
		"COMMON_REPLAY_FAST_FORWARD",
		EV_COMMON_REPLAY_FAST_FORWARD,
		"",
		_L("move replay fast forward")
	},
	{
		"COMMON_REPLAY_FAST_BACKWARD",
		EV_COMMON_REPLAY_FAST_BACKWARD,
		"",
		_L("move replay fast backward")
	},
	{
		"AIRPLANE_AIRBRAKES_NONE",
		EV_AIRPLANE_AIRBRAKES_NONE,
		"",
		_L("no airbrakes")
	},
	{
		"AIRPLANE_AIRBRAKES_FULL",
		EV_AIRPLANE_AIRBRAKES_FULL,
		"",
		_L("full airbrakes")
	},
	{
		"AIRPLANE_AIRBRAKES_LESS",
		EV_AIRPLANE_AIRBRAKES_LESS,
		"",
		_L("less airbrakes")
	},
	{
		"AIRPLANE_AIRBRAKES_MORE",
		EV_AIRPLANE_AIRBRAKES_MORE,
		"",
		_L("more airbrakes")
	},
	{
		"AIRPLANE_THROTTLE",
		EV_AIRPLANE_THROTTLE,
		"",
		_L("airplane throttle")
	},
	{
		"COMMON_TRUCK_REMOVE",
		EV_COMMON_TRUCK_REMOVE,
		"",
		_L("delete current truck")
	},
	{
		"COMMON_NETCHATDISPLAY",
		EV_COMMON_NETCHATDISPLAY,
		"",
		_L("display or hide net chat")
	},
	{
		"COMMON_NETCHATMODE",
		EV_COMMON_NETCHATMODE,
		"",
		_L("toggle between net chat display modes")
	},
	{
		"CHARACTER_ROT_UP",
		EV_CHARACTER_ROT_UP,
		"",
		_L("rotate view up")
	},
	{
		"CHARACTER_ROT_DOWN",
		EV_CHARACTER_ROT_DOWN,
		"rotate view down",
		_L("rotate view down")
	},
	{
		"CHARACTER_UP",
		EV_CHARACTER_UP,
		"",
		_L("move character up")
	},
	{
		"CHARACTER_DOWN",
		EV_CHARACTER_DOWN,
		"",
		_L("move character down")
	},

	{"", -1, "", ""},
};


#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#define strnlen(str,len) strlen(str)
#endif

//Use this define to signify OIS will be used as a DLL
//(so that dll import/export macros are in effect)
#define OIS_DYNAMIC_LIB
#include <OIS.h>

#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
#include <X11/Xlib.h>
#include <linux/LinuxMouse.h>
#endif

#ifndef NOOGRE
#include "ogreconsole.h"
#endif

using namespace std;
using namespace Ogre;
using namespace OIS;

// singleton pattern
InputEngine* InputEngine::myInstance = 0;

InputEngine & InputEngine::Instance ()
{
	if (myInstance == 0)
		myInstance = new InputEngine;
	return *myInstance;
}

bool InputEngine::instanceExists()
{
	return (myInstance != 0);
}
// Constructor takes a RenderWindow because it uses that to determine input context
InputEngine::InputEngine() : mInputManager(0), mMouse(0), mKeyboard(0), captureMode(false), mappingLoaded(false),free_joysticks(0)
{
	for(int i=0;i<MAX_JOYSTICKS;i++) mJoy[i]=0;
#ifndef NOOGRE
	LogManager::getSingleton().logMessage("*** Loading OIS ***");
#endif
	initAllKeys();
}

InputEngine::~InputEngine()
{
#ifndef NOOGRE
	LogManager::getSingleton().logMessage("*** Terminating destructor ***");
#endif
	destroy();
}

void InputEngine::destroy()
{
	if( mInputManager )
	{
#ifndef NOOGRE
		LogManager::getSingleton().logMessage("*** Terminating OIS ***");
#endif
		if(mMouse)
		{
			mInputManager->destroyInputObject( mMouse );
			mMouse=0;
		}
		if(mKeyboard)
		{
			mInputManager->destroyInputObject( mKeyboard );
			mKeyboard=0;
		}
		if(mJoy)
		{
			for(int i=0;i<MAX_JOYSTICKS;i++)
			{
				if(!mJoy[i]) continue;
				mInputManager->destroyInputObject(mJoy[i]);
				mJoy[i] = 0;
			}
		}

		OIS::InputManager::destroyInputSystem(mInputManager);
		mInputManager = 0;
	}
}


bool InputEngine::setup(size_t hwnd, bool capture, bool capturemouse, int _grabMode)
{
	grabMode = _grabMode;
#ifndef NOOGRE
	LogManager::getSingleton().logMessage("*** Initializing OIS ***");
#endif
	//try to delete old ones first (linux can only handle one at a time)
	destroy();
	captureMode = capture;
	recordChat=false;
	if(captureMode)
	{
		//size_t hWnd = 0;
		//win->getCustomAttribute("WINDOW", &hWnd);
		ParamList pl;
		String hwnd_str = Ogre::StringConverter::toString(hwnd);
		pl.insert(OIS::ParamList::value_type("WINDOW", hwnd_str));

		if(grabMode == GRAB_ALL)
		{
		} else if(grabMode == GRAB_DYNAMICALLY || grabMode == GRAB_NONE)
		{
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
			pl.insert(OIS::ParamList::value_type("x11_mouse_hide", "false"));
			pl.insert(OIS::ParamList::value_type("XAutoRepeatOn", "false"));
			pl.insert(OIS::ParamList::value_type("x11_mouse_grab", "false"));
			pl.insert(OIS::ParamList::value_type("x11_keyboard_grab", "false"));
#endif
		}
#ifndef NOOGRE
		LogManager::getSingleton().logMessage("*** OIS WINDOW: "+hwnd_str);
#endif //NOOGRE

		mInputManager = OIS::InputManager::createInputSystem(pl);

#ifndef NOOGRE
		//Print debugging information
		unsigned int v = mInputManager->getVersionNumber();
		LogManager::getSingleton().logMessage("OIS Version: " + StringConverter::toString(v>>16) + String(".") + StringConverter::toString((v>>8) & 0x000000FF) + String(".") + StringConverter::toString(v & 0x000000FF));
		LogManager::getSingleton().logMessage("+ Release Name: " + mInputManager->getVersionName());
		LogManager::getSingleton().logMessage("+ Manager: " + mInputManager->inputSystemName());
		LogManager::getSingleton().logMessage("+ Total Keyboards: " + StringConverter::toString(mInputManager->getNumberOfDevices(OISKeyboard)));
		LogManager::getSingleton().logMessage("+ Total Mice: " + StringConverter::toString(mInputManager->getNumberOfDevices(OISMouse)));
		LogManager::getSingleton().logMessage("+ Total JoySticks: " + StringConverter::toString(mInputManager->getNumberOfDevices(OISJoyStick)));

		//List all devices
		OIS::DeviceList list = mInputManager->listFreeDevices();
		for(OIS::DeviceList::iterator i = list.begin(); i != list.end(); ++i )
			LogManager::getSingleton().logMessage("* Device: " + String(mOISDeviceType[i->first]) + String(" Vendor: ") + i->second);
#endif //NOOGRE

		//Create all devices (We only catch joystick exceptions here, as, most people have Key/Mouse)
		mKeyboard = static_cast<Keyboard*>(mInputManager->createInputObject( OISKeyboard, true ));
		mKeyboard->setTextTranslation(OIS::Keyboard::Unicode);


		try
		{
			//This demo uses at most 10 joysticks - use old way to create (i.e. disregard vendor)
			int numSticks = std::min(mInputManager->getNumberOfDevices(OISJoyStick), 10);
			free_joysticks=0;
			for(int i = 0; i < numSticks; ++i)
			{
				mJoy[i] = (JoyStick*)mInputManager->createInputObject(OISJoyStick, true);
				mJoy[i]->setEventCallback(this);
				free_joysticks++;

#ifndef NOOGRE
				LogManager::getSingleton().logMessage("Creating Joystick " + StringConverter::toString(i + 1) + " (" + mJoy[i]->vendor() + ")");
				LogManager::getSingleton().logMessage("* Axes: " + StringConverter::toString(mJoy[i]->getNumberOfComponents(OIS_Axis)));
				LogManager::getSingleton().logMessage("* Sliders: " + StringConverter::toString(mJoy[i]->getNumberOfComponents(OIS_Slider)));
				LogManager::getSingleton().logMessage("* POV/HATs: " + StringConverter::toString(mJoy[i]->getNumberOfComponents(OIS_POV)));
				LogManager::getSingleton().logMessage("* Buttons: " + StringConverter::toString(mJoy[i]->getNumberOfComponents(OIS_Button)));
				LogManager::getSingleton().logMessage("* Vector3: " + StringConverter::toString(mJoy[i]->getNumberOfComponents(OIS_Vector3)));
#endif //NOOGRE
			}
		}
#ifndef NOOGRE
		catch(OIS::Exception &ex)
		{
			LogManager::getSingleton().logMessage(String("Exception raised on joystick creation: ") + String(ex.eText));
		}
#else  //NOOGRE
		catch(...)
		{
		}
#endif //NOOGRE

		if(capturemouse)
			mMouse = static_cast<Mouse*>(mInputManager->createInputObject( OISMouse, true ));

		//Set initial mouse clipping size
		//windowResized(win);

		// set Callbacks
		mKeyboard->setEventCallback(this);
		if(capturemouse)
			mMouse->setEventCallback(this);
		
		// init states (not required for keyboard)
		if(capturemouse)
			mouseState = mMouse->getMouseState();
		if(free_joysticks)
		{
			for(int i=0;i<free_joysticks;i++)
				joyState[i] = mJoy[i]->getJoyStickState();
		}
	}
	//this becomes more and more convoluted!
#ifdef NOOGRE
	// we will load the mapping manually
#else //NOOGRE
	if(!mappingLoaded)
	{
		if (!loadMapping())
		{
			return false;
		} else
			completeMissingEvents();
	}
#endif //NOOGRE
	return true;
}

void InputEngine::grabMouse(bool enable)
{
	static int lastmode = -1;
	if(!mMouse)
		return;
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
	if((enable && lastmode == 0) || (!enable && lastmode == 1) || (lastmode == -1))
	{
		LogManager::getSingleton().logMessage("*** mouse grab: " + StringConverter::toString(enable));
		((LinuxMouse *)mMouse)->grab(enable);
		lastmode = enable?1:0;
	}
#endif
}

void InputEngine::hideMouse(bool visible)
{
	static int mode = -1;
	if(!mMouse)
		return;
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
	if((visible && mode == 0) || (!visible && mode == 1) || mode == -1)
	{
		((LinuxMouse *)mMouse)->hide(visible);
		mode = visible?1:0;
	}
#endif
}

void InputEngine::setMousePosition(int x, int y, bool padding)
{
	if(!mMouse)
		return;
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
	// padding ensures that the mouse has a safety area at the window's borders
//	((LinuxMouse *)mMouse)->setMousePosition(x, y, padding);
#endif
}

OIS::MouseState InputEngine::getMouseState()
{
	static float mX=999999, mY=999999;
	static int mode = -1;
	if(mode == -1)
	{
#ifndef NOOGRE
		// try to find the correct location!
		mX = StringConverter::parseReal(SETTINGS.getSetting("MouseSensX"));
		mY = StringConverter::parseReal(SETTINGS.getSetting("MouseSensY"));
		LogManager::getSingleton().logMessage("Mouse X sens: " + StringConverter::toString((Real)mX));
		LogManager::getSingleton().logMessage("Mouse Y sens: " + StringConverter::toString((Real)mY));
		mode = 1;
		if(mX == 0 || mY ==0)
			mode = 2;
#else
		// no scaling without ogre
		mode = 2;
#endif
	}

	OIS::MouseState m;
	if(mMouse)
	{
		m = mMouse->getMouseState();
		if(mode == 1)
		{
			m.X.rel = (int)((float)m.X.rel * mX);
			m.Y.rel = (int)((float)m.X.rel * mY);
		}
	}
	return m;
}

bool InputEngine::fileExists(char* filename)
{
	FILE* f = fopen(filename, "rb");
	if(f != NULL) {
		fclose(f);
		return true;
	}
	return false;
}

Ogre::String InputEngine::getKeyNameForKeyCode(OIS::KeyCode keycode)
{
	if(keycode == KC_LSHIFT || keycode == KC_RSHIFT)
		return "SHIFT";
	if(keycode == KC_LCONTROL || keycode == KC_RCONTROL)
		return "CTRL";
	if(keycode == KC_LMENU || keycode == KC_RMENU)
		return "ALT";
	for(allit = allkeys.begin();allit != allkeys.end();allit++)
	{
		if(allit->second == keycode)
			return allit->first;
	}
	return "unkown";
}

void InputEngine::Capture()
{
	if(mKeyboard) mKeyboard->capture();
	if(mMouse) mMouse->capture();
	if(free_joysticks) 
		for(int i=0;i<free_joysticks;i++)
			if(mJoy[i]) mJoy[i]->capture();
}

void InputEngine::windowResized(RenderWindow* rw)
{
	if(!mMouse)
		return;
	//update mouse area
	unsigned int width, height, depth;
	int left, top;
	rw->getMetrics(width, height, depth, left, top);
	const OIS::MouseState &ms = mMouse->getMouseState();
	ms.width = width;
	ms.height = height;
}

/* --- Joystik Events ------------------------------------------ */
bool InputEngine::buttonPressed( const OIS::JoyStickEvent &arg, int button )
{
	inputsChanged=true;
	//LogManager::getSingleton().logMessage("*** buttonPressed " + StringConverter::toString(button));
	int i = arg.device->getID();
	joyState[i] = arg.state;
	return true;
}

bool InputEngine::buttonReleased( const OIS::JoyStickEvent &arg, int button )
{
	inputsChanged=true;
	//LogManager::getSingleton().logMessage("*** buttonReleased " + StringConverter::toString(button));
	int i = arg.device->getID();
	joyState[i] = arg.state;
	return true;
}

bool InputEngine::axisMoved( const OIS::JoyStickEvent &arg, int axis )
{
	inputsChanged=true;
	//LogManager::getSingleton().logMessage("*** axisMoved " + StringConverter::toString(axis) + " / " + StringConverter::toString((int)(arg.state.mAxes[axis].abs / (float)(mJoy->MAX_AXIS/100))));
	int i = arg.device->getID();
	joyState[i] = arg.state;
	return true;
}

bool InputEngine::sliderMoved( const OIS::JoyStickEvent &arg, int )
{
	inputsChanged=true;
	//LogManager::getSingleton().logMessage("*** sliderMoved");
	int i = arg.device->getID();
	joyState[i] = arg.state;
	return true;
}

bool InputEngine::povMoved( const OIS::JoyStickEvent &arg, int )
{
	inputsChanged=true;
	//LogManager::getSingleton().logMessage("*** povMoved");
	int i = arg.device->getID();
	joyState[i] = arg.state;
	return true;
}

/* --- Key Events ------------------------------------------ */
bool InputEngine::keyPressed( const OIS::KeyEvent &arg )
{
#ifndef NOOGRE
# ifdef ANGELSCRIPT
	if(OgreConsole::getSingleton().getVisible())
	{
		OgreConsole::getSingleton().onKeyPressed(arg);
		return true;
	}
# endif
#endif

	//LogManager::getSingleton().logMessage("*** keyPressed");
	if(keyState[arg.key] != 1)
		inputsChanged=true;
	keyState[arg.key] = 1;

	if(recordChat)
	{
		// chatting stuff
		if (keyInput.size()<255)
		{
			if ((arg.key==OIS::KC_DELETE || arg.key==OIS::KC_BACK) && keyInput.size()>0)
			{
				keyInput = keyInput.substr(0, keyInput.size()-1);
#ifndef NOOGRE
				NETCHAT.setEnterText("^7"+keyInput, true, true);
#endif
			}

			// exclude control keys
			if(arg.text > 20)
			{
				keyInput.push_back(arg.text);
#ifndef NOOGRE
				NETCHAT.setEnterText("^7"+keyInput, true, true);
#endif
			}
		}
	}

#ifndef NOOGRE
	MYGUI.keyPressed(arg);
#endif

	return true;
}

bool InputEngine::keyReleased( const OIS::KeyEvent &arg )
{
	//LogManager::getSingleton().logMessage("*** keyReleased");
	if(keyState[arg.key] != 0)
		inputsChanged=true;
	keyState[arg.key] = 0;
#ifndef NOOGRE
	MYGUI.keyReleased(arg);
#endif
	return true;
}

/* --- Mouse Events ------------------------------------------ */
bool InputEngine::mouseMoved( const OIS::MouseEvent &arg )
{
	//APP.mGUISystem->injectOISMouseMove(arg);
	//LogManager::getSingleton().logMessage("*** mouseMoved");
	inputsChanged=true;
	mouseState = arg.state;
#ifndef NOOGRE
	MYGUI.mouseMoved(arg);
#endif
	return true;
}

bool InputEngine::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
	//APP.mGUISystem->injectOISMouseButtonDown(id);
	//LogManager::getSingleton().logMessage("*** mousePressed");
	inputsChanged=true;
	mouseState = arg.state;
#ifndef NOOGRE
	MYGUI.mousePressed(arg, id);
#endif
	return true;
}

bool InputEngine::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id )
{
	//APP.mGUISystem->injectOISMouseButtonUp(id);
	//LogManager::getSingleton().logMessage("*** mouseReleased");
	inputsChanged=true;
	mouseState = arg.state;
#ifndef NOOGRE
	MYGUI.mouseReleased(arg, id);
#endif
	return true;
}

/* --- Custom Methods ------------------------------------------ */
void InputEngine::prepareShutdown()
{
#ifndef NOOGRE
	LogManager::getSingleton().logMessage("*** Inputsystem prepare for shutdown ***");
#endif
	destroy();
}


void InputEngine::resetKeys()
{
	for ( map<int, bool>::iterator iter = keyState.begin(); iter != keyState.end(); ++iter)
	{
		iter->second = false;
	}
}

bool InputEngine::getEventBoolValue(int eventID)
{
	return (getEventValue(eventID) > 0.5f);
}

bool InputEngine::getEventBoolValueBounce(int eventID, float time)
{
	if(event_times[eventID] > 0)
		return false;
	else
	{
		bool res = getEventBoolValue(eventID);
		if(res) event_times[eventID] = time;
		return res;
	}
}

float InputEngine::getEventBounceTime(int eventID)
{
	return event_times[eventID];
}

void InputEngine::updateKeyBounces(float dt)
{
	for(std::map<int, float>::iterator it=event_times.begin(); it!=event_times.end(); it++)
	{
		if(it->second > 0)
			it->second -= dt;
		//else
		// erase element?
	}
}

float InputEngine::deadZone(float axisValue, float dz)
{
	// no deadzone?
	if(dz < 0.0001f)
		return axisValue;

	// check for deadzone
	if (fabs(axisValue) < dz)
		// dead zone case
		return 0.0f;
	else
		// non-deadzone, remap the remaining part
		return (axisValue - dz) * (1.0f / (1.0f-dz));
	return axisValue;
}

float InputEngine::axisLinearity(float axisValue, float linearity)
{
	return (axisValue * linearity);
}

float InputEngine::logval(float val)
{
	if (val>0) return log10(1.0/(1.1-val))/1.0;
	if (val==0) return 0;
	return -log10(1.0/(1.1+val))/1.0;
}

void InputEngine::smoothValue(float &ref, float value, float rate)
{
	if(value < -1) value = -1;
	if(value > 1) value = 1;
	// smooth!
	if (ref > value)
	{
		ref -= rate;
		if (ref < value)
			ref = value;
	}
	else if (ref < value)
		ref += rate;
}

String InputEngine::getEventCommand(int eventID)
{
	std::vector<event_trigger_t> t_vec = events[eventID];
	if(t_vec.size() > 0)
		return String(t_vec[0].configline);
	return "";
}

event_trigger_t *InputEngine::getEventBySUID(int suid)
{
	std::map<int, std::vector<event_trigger_t> >::iterator a;
	std::vector<event_trigger_t>::iterator b;
	for(a = events.begin();a != events.end(); a++)
	{
		for(b = a->second.begin();b != a->second.end(); b++)
		{
			if(b->suid == suid)
				return &(*b);
		}
	}
	return 0;
}

bool InputEngine::deleteEventBySUID(int suid)
{
	std::map<int, std::vector<event_trigger_t> >::iterator a;
	std::vector<event_trigger_t>::iterator b;
	for(a = events.begin();a != events.end(); a++)
	{
		for(b = a->second.begin();b != a->second.end(); b++)
		{
			if(b->suid == suid)
			{
				a->second.erase(b);
				return true;
			}
		}
	}
	return false;
}

bool InputEngine::isEventDefined(int eventID)
{
	std::vector<event_trigger_t> t_vec = events[eventID];
	if(t_vec.size() > 0)
	{
		if(t_vec[0].eventtype != ET_NONE)
			return true;
	}
	return false;
}

int InputEngine::getKeboardKeyForCommand(int eventID)
{
	float returnValue = 0;
	std::vector<event_trigger_t> t_vec = events[eventID];
	for(std::vector<event_trigger_t>::iterator i = t_vec.begin(); i != t_vec.end(); i++)
	{
		event_trigger_t t = *i;
		float value = 0;
		if(t.eventtype == ET_Keyboard)
			return t.keyCode;
		return -1;
	}
	return -1;
}

bool InputEngine::isEventAnalog(int eventID)
{
	std::vector<event_trigger_t> t_vec = events[eventID];
	if(t_vec.size() > 0)
	{
		if(t_vec[0].eventtype == ET_MouseAxisX || t_vec[0].eventtype == ET_MouseAxisY || t_vec[0].eventtype == ET_MouseAxisZ || t_vec[0].eventtype == ET_JoystickAxisAbs || t_vec[0].eventtype == ET_JoystickAxisRel || t_vec[0].eventtype == ET_JoystickSliderX || t_vec[0].eventtype == ET_JoystickSliderY)
			return true;
		else
			return false;
	}
	return false;
}

float InputEngine::getEventValue(int eventID, bool pure)
{
	float returnValue = 0;
	std::vector<event_trigger_t> t_vec = events[eventID];
	for(std::vector<event_trigger_t>::iterator i = t_vec.begin(); i != t_vec.end(); i++)
	{
		event_trigger_t t = *i;
		float value = 0;
		switch(t.eventtype)
		{
			case ET_NONE:
				break;
			case ET_Keyboard:
				if(!keyState[t.keyCode])
					break;

				// only use explicite mapping, if two keys with different modifiers exist, i.e. F1 and SHIFT+F1.
				// check for modificators
				if (t.explicite)
				{
					if(t.ctrl != (keyState[KC_LCONTROL] || keyState[KC_RCONTROL]))
						break;
					if(t.shift != (keyState[KC_LSHIFT] || keyState[KC_RSHIFT]))
						break;
					if(t.alt != (keyState[KC_LMENU] || keyState[KC_RMENU]))
						break;
				} else {
					if(t.ctrl && !(keyState[KC_LCONTROL] || keyState[KC_RCONTROL]))
						break;
					if(t.shift && !(keyState[KC_LSHIFT] || keyState[KC_RSHIFT]))
						break;
					if(t.alt && !(keyState[KC_LMENU] || keyState[KC_RMENU]))
						break;
				}
				value = 1;
				break;
			case ET_MouseButton:
				//if(t.mouseButtonNumber == 0)
				// TODO: FIXME
				value = mouseState.buttonDown(MB_Left);
				break;
			case ET_MouseAxisX:
				value = mouseState.X.abs / 32767;
				break;
			case ET_MouseAxisY:
				value = mouseState.Y.abs / 32767;
				break;
			case ET_MouseAxisZ:
				value = mouseState.Z.abs / 32767;
				break;
			case ET_JoystickButton:
				{
					if(t.joystickNumber > free_joysticks || !mJoy[t.joystickNumber])
					{
						value=0;
						continue;
					}
					if(t.joystickButtonNumber >= (int)mJoy[t.joystickNumber]->getNumberOfComponents(OIS_Button))
					{
#ifndef NOOGRE
						LogManager::getSingleton().logMessage("*** Joystick has not enough buttons for mapping: need button "+StringConverter::toString(t.joystickButtonNumber) + ", availabe buttons: "+StringConverter::toString(mJoy[t.joystickNumber]->getNumberOfComponents(OIS_Button)));
#endif
						value=0;
						continue;
					}
					value = joyState[t.joystickNumber].mButtons[t.joystickButtonNumber];
				}
				break;
			case ET_JoystickAxisRel:
			case ET_JoystickAxisAbs:
				{
					if(t.joystickNumber > free_joysticks || !mJoy[t.joystickNumber])
					{
						value=0;
						continue;
					}
					if(t.joystickAxisNumber >= (int)joyState[t.joystickNumber].mAxes.size())
					{
#ifndef NOOGRE
						LogManager::getSingleton().logMessage("*** Joystick has not enough axis for mapping: need axe "+StringConverter::toString(t.joystickAxisNumber) + ", availabe axis: "+StringConverter::toString(joyState[t.joystickNumber].mAxes.size()));
#endif
						value=0;
						continue;
					}
					Axis axe = joyState[t.joystickNumber].mAxes[t.joystickAxisNumber];

					if(t.eventtype == ET_JoystickAxisRel)
					{
						value = (float)axe.rel / (float)mJoy[t.joystickNumber]->MAX_AXIS;
					}
					else
					{
						value = (float)axe.abs / (float)mJoy[t.joystickNumber]->MAX_AXIS;
						switch(t.joystickAxisRegion)
						{
						case 0:
							// normal case, full axis used
							value = (value + 1)/2;
							break;
						case -1:
							// lower range used
							if(value > 0)
								value = 0;
							else
								value = value * -1.0;
							break;
						case 1:
							// upper range used
							if(value < 0)
								value = 0;
							break;
						}

						if(t.joystickAxisHalf)
						{
							// XXX: TODO: write this
							//float a = (double)((value+1.0)/2.0);
							//float b = (double)(1.0-(value+1.0)/2.0);
							//LogManager::getSingleton().logMessage("half: "+StringConverter::toString(value)+" / "+StringConverter::toString(a)+" / "+StringConverter::toString(b));
							//no dead zone in half axis
							value = (1.0 + value) / 2.0;
							if (t.joystickAxisReverse)
								value = 1.0 - value;
							if(!pure)
								value = axisLinearity(value, t.joystickAxisLinearity);
						}else
						{
							//LogManager::getSingleton().logMessage("not half: "+StringConverter::toString(value)+" / "+StringConverter::toString(deadZone(value, t.joystickAxisDeadzone)) +" / "+StringConverter::toString(t.joystickAxisDeadzone) );
							if(!pure)
								// no deadzone when using oure value
								value = deadZone(value, t.joystickAxisDeadzone);
							if (t.joystickAxisReverse)
								value = 1-value;
							if(!pure)
								value = axisLinearity(value, t.joystickAxisLinearity);
						}
						// digital mapping of analog axis
						if(t.joystickAxisUseDigital)
							if(value >= 0.5)
								value = 1;
							else
								value = 0;
					}
				}
				break;
			case ET_JoystickPov:
				{
					if(t.joystickNumber > free_joysticks || !mJoy[t.joystickNumber])
					{
						value=0;
						continue;
					}
					if(t.joystickPovNumber >= (int)mJoy[t.joystickNumber]->getNumberOfComponents(OIS_POV))
					{
#ifndef NOOGRE
						LogManager::getSingleton().logMessage("*** Joystick has not enough POVs for mapping: need POV "+StringConverter::toString(t.joystickPovNumber) + ", availabe POVs: "+StringConverter::toString(mJoy[t.joystickNumber]->getNumberOfComponents(OIS_POV)));
#endif
						value=0;
						continue;
					}
					if(joyState[t.joystickNumber].mPOV[t.joystickPovNumber].direction & t.joystickPovDirection)
						value = 1;
					else
						value = 0;
				}
				break;
			case ET_JoystickSliderX:
				{
					if(t.joystickNumber > free_joysticks || !mJoy[t.joystickNumber])
					{
						value=0;
						continue;
					}
					value = (float)joyState[t.joystickNumber].mSliders[t.joystickSliderNumber].abX / (float)mJoy[t.joystickNumber]->MAX_AXIS;
					value = (value + 1)/2; // full axis
					if(t.joystickSliderReverse)
						value = 1.0 - value; // reversed
				}
				break;
			case ET_JoystickSliderY:
				{
					if(t.joystickNumber > free_joysticks || !mJoy[t.joystickNumber])
					{
						value=0;
						continue;
					}
					value = (float)joyState[t.joystickNumber].mSliders[t.joystickSliderNumber].abY / (float)mJoy[t.joystickNumber]->MAX_AXIS;
					value = (value + 1)/2; // full axis
					if(t.joystickSliderReverse)
						value = 1.0 - value; // reversed
				}
				break;
		}
		// only return if grater zero, otherwise check all other bombinations
		if(value > returnValue)
			returnValue = value;
	}
	return returnValue;
}

bool InputEngine::isKeyDown(OIS::KeyCode key)
{
	return this->mKeyboard->isKeyDown(key);
}

Ogre::String InputEngine::getDeviceName(event_trigger_t evt)
{
	switch(evt.eventtype)
	{
	case ET_NONE:
		return "None";
	case ET_Keyboard:
		return "Keyboard";
	case ET_MouseButton:
	case ET_MouseAxisX:
	case ET_MouseAxisY:
	case ET_MouseAxisZ: 
		return "Mouse";
	case ET_JoystickButton:
	case ET_JoystickAxisAbs:
	case ET_JoystickAxisRel:
	case ET_JoystickPov:
	case ET_JoystickSliderX:
	case ET_JoystickSliderY:
		return "Joystick: " + getJoyVendor(evt.joystickNumber);
	}
	return "unkown";	
}

Ogre::String InputEngine::getEventTypeName(int type)
{
	switch(type)
	{
	case ET_NONE: return "None";
	case ET_Keyboard: return "Keyboard";
	case ET_MouseButton: return "MouseButton";
	case ET_MouseAxisX: return "MouseAxisX";
	case ET_MouseAxisY: return "MouseAxisY";
	case ET_MouseAxisZ: return "MouseAxisZ";
	case ET_JoystickButton: return "JoystickButton";
	case ET_JoystickAxisAbs: return "JoystickAxis";
	case ET_JoystickAxisRel: return "JoystickAxis";
	case ET_JoystickPov: return "JoystickPov";
	case ET_JoystickSliderX: return "JoystickSliderX";
	case ET_JoystickSliderY: return "JoystickSliderY";
	}
	return "unkown";
}

void InputEngine::addEvent(int eventID, event_trigger_t t)
 {
	static int counter=0;
	counter++;
	t.suid = counter;

	if(eventID == -1)
		//unkown event, discard
		return;
	if(events.find(eventID) == events.end())
	{
		events[eventID] = std::vector<event_trigger_t>();
		events[eventID].clear();
	}
	events[eventID].push_back(t);
}

bool InputEngine::processLine(char *line)
{
	static Ogre::String cur_comment = "";

	char eventName[255]="", evtype[255]="";
	const char delimiters[] = "+";
	size_t linelen = strnlen(line, 1024);
	enum eventtypes eventtype = ET_NONE;

	int joyNo = 0;
	float defaultDeadzone = 0.1f;
	float defaultLinearity = 1.0f;
	if (line[0]==';' || linelen < 5)
	{
		cur_comment += line;;
		return false;
	}
	sscanf(line, "%s %s", eventName, evtype);
	if(strnlen(eventName, 255) == 0 || strnlen(evtype, 255) == 0)
		return false;

	if(!strncmp(evtype, "Keyboard", 8)) eventtype = ET_Keyboard;
	else if(!strncmp(evtype, "MouseButton", 10)) eventtype = ET_MouseButton;
	else if(!strncmp(evtype, "MouseAxisX", 9)) eventtype = ET_MouseAxisX;
	else if(!strncmp(evtype, "MouseAxisY", 9)) eventtype = ET_MouseAxisY;
	else if(!strncmp(evtype, "MouseAxisZ", 9)) eventtype = ET_MouseAxisZ;
	else if(!strncmp(evtype, "JoystickButton", 14)) eventtype = ET_JoystickButton;
	else if(!strncmp(evtype, "JoystickAxis", 12)) eventtype = ET_JoystickAxisAbs;
	//else if(!strncmp(evtype, "JoystickAxis", 250)) eventtype = ET_JoystickAxisRel;
	else if(!strncmp(evtype, "JoystickPov", 11)) eventtype = ET_JoystickPov;
	else if(!strncmp(evtype, "JoystickSliderX", 15)) eventtype = ET_JoystickSliderX;
	else if(!strncmp(evtype, "JoystickSliderY", 15)) eventtype = ET_JoystickSliderY;
	else if(!strncmp(evtype, "None", 4)) eventtype = ET_NONE;

	switch(eventtype)
	{
	case ET_Keyboard:
		{
			char keycodes[255], *keycode=0;
			OIS::KeyCode key = KC_UNASSIGNED;
			sscanf(line, "%s %s %s", eventName, evtype, keycodes);
			// seperate all keys and construct the key combination
			//LogManager::getSingleton().logMessage("try to add key: " + String(keyname)+","+ String(evtype)+","+String(keycodes));
			bool alt=false;
			bool shift=false;
			bool ctrl=false;
			bool expl=false;
			char keycodes_work[255] = "";
			strncpy(keycodes_work, keycodes, 255);
			char *token = strtok(keycodes_work, delimiters);
			while (token != NULL)
			{
				if (strncmp(token, "SHIFT", 5) == 0)
					shift=true;
				else if (strncmp(token, "CTRL", 4) == 0)
					ctrl=true;
				else if (strncmp(token, "ALT", 3) == 0)
					alt=true;
				else if (strncmp(token, "EXPL", 4) == 0)
					expl=true;
				keycode = token;
				token = strtok(NULL, delimiters);
			}

			allit = allkeys.find(keycode);
			if(allit == allkeys.end())
			{
#ifndef NOOGRE
				LogManager::getSingleton().logMessage("unkown key: " + string(keycodes));
#endif
				key = KC_UNASSIGNED;
			} else {
				//LogManager::getSingleton().logMessage("found key: " + string(keycode) + " = " + StringConverter::toString((int)key));
				key = allit->second;
			}
			int eventID = resolveEventName(String(eventName));
			if(eventID == -1) return false;
			event_trigger_t t_key = newEvent();
			//memset(&t_key, 0, sizeof(event_trigger_t));
			t_key.eventtype = ET_Keyboard;
			t_key.shift = shift;
			t_key.ctrl = ctrl;
			t_key.alt = alt;
			t_key.explicite = expl;
			t_key.keyCode = key;
			strncpy(t_key.configline, keycodes, 128);
			strncpy(t_key.group, getEventGroup(eventName).c_str(), 128);
			strncpy(t_key.tmp_eventname, eventName, 128);

			strncpy(t_key.comments, cur_comment.c_str(), 1024);
			cur_comment = "";
			addEvent(eventID, t_key);

#ifndef NOOGRE
			//LogManager::getSingleton().logMessage("adding: " + String(eventName) + ": "+StringConverter::toString((int)key));
#endif
			return true;
		}
	case ET_JoystickButton:
		{
			int buttonNo=0;
			char tmp2[255];
			memset(tmp2, 0 ,255);
			sscanf(line, "%s %s %d %d %s", eventName, evtype, &joyNo, &buttonNo, tmp2);
			event_trigger_t t_joy = newEvent();
			//memset(&t_joy, 0, sizeof(event_trigger_t));
			int eventID = resolveEventName(String(eventName));
			if(eventID == -1) return false;
			t_joy.eventtype = ET_JoystickButton;
			t_joy.joystickNumber = joyNo;
			t_joy.joystickButtonNumber = buttonNo;
			if(!strcmp(tmp2, "!NEW!"))
			{
				strncpy(t_joy.configline, tmp2, 128);
			} else
			{
				char tmp[255];
				sprintf(tmp, "%d", buttonNo);
				strncpy(t_joy.configline, tmp, 128);
			}
			strncpy(t_joy.group, getEventGroup(eventName).c_str(), 128);
			strncpy(t_joy.tmp_eventname, eventName, 128);
			strncpy(t_joy.comments, cur_comment.c_str(), 1024);
			cur_comment = "";
			addEvent(eventID, t_joy);
			return true;
		}
	case ET_JoystickAxisRel:
	case ET_JoystickAxisAbs:
		{
			int axisNo=0;
			char options[250];
			memset(options, 0, 250);
			sscanf(line, "%s %s %d %d %s", eventName, evtype, &joyNo, &axisNo, options);
			int eventID = resolveEventName(String(eventName));
			if(eventID == -1) return false;

			bool half=false;
			bool reverse=false;
			bool linear=false;
			bool relative=false;
			bool usedigital=false;
			float deadzone=defaultDeadzone;
			float linearity=defaultLinearity;
			int jAxisRegion=0;
			// 0 = all
			// -1 = lower
			// 1 = upper
			char tmp[250] = "";
			strncpy(tmp, options, 250);
			char *token = strtok(tmp, delimiters);
			while (token != NULL)
			{
				if (strncmp(token, "HALF", 4) == 0)
					half=true;
				else if (strncmp(token, "REVERSE", 7) == 0)
					reverse=true;
				else if (strncmp(token, "LINEAR", 6) == 0)
					linear=true;
				else if (strncmp(token, "UPPER", 5) == 0)
					jAxisRegion = 1;
				else if (strncmp(token, "LOWER", 5) == 0)
					jAxisRegion = -1;
				else if (strncmp(token, "RELATIVE", 8) == 0)
					relative=true;
				else if (strncmp(token, "DIGITAL", 7) == 0)
					usedigital=true;
				else if (strncmp(token, "DEADZONE", 8) == 0 && strnlen(token, 250) > 9)
				{
					char tmp2[255];
					strcpy(tmp2,token+9);
					deadzone = atof(tmp2);
					//LogManager::getSingleton().logMessage("got deadzone: " + StringConverter::toString(deadzone)+", "+String(tmp2));
				}
				else if (strncmp(token, "LINEARITY", 9) == 0 && strnlen(token, 250) > 10)
				{
					char tmp2[255];
					strcpy(tmp2,token+10);
					linearity = atof(tmp2);
				}
				token = strtok(NULL, delimiters);
			}

			if(relative)
				eventtype = ET_JoystickAxisRel;

			event_trigger_t t_joy = newEvent();
			//memset(&t_joy, 0, sizeof(event_trigger_t));
			t_joy.eventtype = eventtype;
			t_joy.joystickAxisRegion = jAxisRegion;
			t_joy.joystickAxisUseDigital = usedigital;
			t_joy.joystickAxisDeadzone = deadzone;
			t_joy.joystickAxisHalf = half;
			t_joy.joystickAxisLinearity = linearity;
			t_joy.joystickAxisReverse = reverse;
			t_joy.joystickAxisNumber = axisNo;
			t_joy.joystickNumber = joyNo;
			strncpy(t_joy.configline, options, 128);
			strncpy(t_joy.group, getEventGroup(eventName).c_str(), 128);
			strncpy(t_joy.tmp_eventname, eventName, 128);
			strncpy(t_joy.comments, cur_comment.c_str(), 1024);
			cur_comment = "";
			addEvent(eventID, t_joy);
			//LogManager::getSingleton().logMessage("added axis: " + StringConverter::toString(axisNo));
			return true;
		}
	case ET_NONE:
		{
			int eventID = resolveEventName(String(eventName));
			if(eventID == -1) return false;
			event_trigger_t t_none = newEvent();
			t_none.eventtype = eventtype;
			//t_none.configline = "";
			strncpy(t_none.group, getEventGroup(eventName).c_str(), 128);
			strncpy(t_none.tmp_eventname, eventName, 128);
			strncpy(t_none.comments, cur_comment.c_str(), 1024);
			cur_comment = "";
			addEvent(eventID, t_none);
			return true;
		}
	case ET_MouseButton:
	case ET_MouseAxisX:
	case ET_MouseAxisY:
	case ET_MouseAxisZ:
		// no mouse support D:
		return false;
	case ET_JoystickPov:
		{
			int povNumber=0;
			char dir[250];
			memset(dir, 0, 250);
			sscanf(line, "%s %s %d %d %s", eventName, evtype, &joyNo, &povNumber, dir);
			int eventID = resolveEventName(String(eventName));
			if(eventID == -1) return false;

			int direction = OIS::Pov::Centered;
			if(!strcmp(dir, "North")) direction = OIS::Pov::North;
			if(!strcmp(dir, "South")) direction = OIS::Pov::South;
			if(!strcmp(dir, "East")) direction = OIS::Pov::East;
			if(!strcmp(dir, "West")) direction = OIS::Pov::West;
			if(!strcmp(dir, "NorthEast")) direction = OIS::Pov::NorthEast;
			if(!strcmp(dir, "SouthEast")) direction = OIS::Pov::SouthEast;
			if(!strcmp(dir, "NorthWest")) direction = OIS::Pov::NorthWest;
			if(!strcmp(dir, "SouthWest")) direction = OIS::Pov::SouthWest;

			event_trigger_t t_pov = newEvent();
			t_pov.eventtype = eventtype;
			t_pov.joystickNumber = joyNo;
			t_pov.joystickPovNumber = povNumber;
			t_pov.joystickPovDirection = direction;

			strncpy(t_pov.group, getEventGroup(eventName).c_str(), 128);
			strncpy(t_pov.tmp_eventname, eventName, 128);
			strncpy(t_pov.comments, cur_comment.c_str(), 1024);
			cur_comment = "";
			addEvent(eventID, t_pov);
			//LogManager::getSingleton().logMessage("added axis: " + StringConverter::toString(axisNo));
			return true;
		}
	case ET_JoystickSliderX:
	case ET_JoystickSliderY:
		{
			int sliderNumber=0;
			char options[250];
			memset(options, 0, 250);
			sscanf(line, "%s %s %d %d %s", eventName, evtype, &joyNo, &sliderNumber, options);
			int eventID = resolveEventName(String(eventName));
			if(eventID == -1) return false;

			bool reverse=false;
			char tmp[250] = "";
			strncpy(tmp, options, 250);
			char *token = strtok(tmp, delimiters);
			while (token != NULL)
			{
				if (strncmp(token, "REVERSE", 7) == 0)
					reverse=true;

				token = strtok(NULL, delimiters);
			}

			event_trigger_t t_slider = newEvent();
			t_slider.eventtype = eventtype;
			t_slider.joystickNumber = joyNo;
			t_slider.joystickSliderNumber = sliderNumber;
			t_slider.joystickSliderReverse = reverse;
			strncpy(t_slider.group, getEventGroup(eventName).c_str(), 128);
			strncpy(t_slider.tmp_eventname, eventName, 128);
			strncpy(t_slider.comments, cur_comment.c_str(), 1024);
			cur_comment = "";
			addEvent(eventID, t_slider);
			//LogManager::getSingleton().logMessage("added axis: " + StringConverter::toString(axisNo));
			return true;
		}
	default:
		return false;
	}
	return false;
}

int InputEngine::getCurrentJoyButton(int &joystickNumber, int &button)
{
	for(int j=0;j<free_joysticks;j++)
	{
		for(int i=0;i<(int)joyState[j].mButtons.size();i++)
		{
			if(joyState[j].mButtons[i])
			{
				joystickNumber = j;
				button = i;
				return 1;
			}
		}
	}
	return 0;
}

event_trigger_t InputEngine::newEvent()
{
	event_trigger_t res;
	memset(&res, 0, sizeof(event_trigger_t));
	return res;
}

int InputEngine::getJoyComponentCount(OIS::ComponentType type, int joystickNumber)
{
	if(joystickNumber > free_joysticks || !mJoy[joystickNumber]) return 0;
	return mJoy[joystickNumber]->getNumberOfComponents(type);
}

std::string InputEngine::getJoyVendor(int joystickNumber)
{
	if(joystickNumber > free_joysticks || !mJoy[joystickNumber]) return "unkown";
	return mJoy[joystickNumber]->vendor();
}

JoyStickState *InputEngine::getCurrentJoyState(int joystickNumber)
{
	if(joystickNumber > free_joysticks) return 0;
	return &joyState[joystickNumber];
}


int InputEngine::getCurrentKeyCombo(Ogre::String *combo)
{
	std::map<int, bool>::iterator i;
	int keyCounter = 0;
	int modCounter = 0;

	// list all modificators first
	for(i = keyState.begin();i!=keyState.end();i++)
	{
		if(i->second)
		{
			if(i->first != KC_LSHIFT && i->first != KC_RSHIFT && i->first != KC_LCONTROL && i->first != KC_RCONTROL && i->first != KC_LMENU && i->first != KC_RMENU)
				continue;
			modCounter++;
			Ogre::String keyName = getKeyNameForKeyCode((OIS::KeyCode)i->first);
			if(*combo == "")
				*combo = keyName;
			else
				*combo = *combo + "+" + keyName;
		}
	}

	// now list all keys
	for(i = keyState.begin();i!=keyState.end();i++)
	{
		if(i->second)
		{
			if(i->first == KC_LSHIFT || i->first == KC_RSHIFT || i->first == KC_LCONTROL || i->first == KC_RCONTROL || i->first == KC_LMENU || i->first == KC_RMENU)
				continue;
			Ogre::String keyName = getKeyNameForKeyCode((OIS::KeyCode)i->first);
			if(*combo == "")
				*combo = keyName;
			else
				*combo = *combo + "+" + keyName;
			keyCounter++;
		}
	}

	//
	if(modCounter > 0 && keyCounter == 0)
	{
		return -modCounter;
	} else if(keyCounter==0 && modCounter == 0)
	{
		*combo = "(Please press a key)";
		return 0;
	}
	return keyCounter;
}

Ogre::String InputEngine::getEventGroup(Ogre::String eventName)
{
	const char delimiters[] = "_";
	char tmp[250] = "";
	strncpy(tmp, eventName.c_str(), 250);
	char *token = strtok(tmp, delimiters);
	while (token != NULL)
		return Ogre::String(token);
	return "";
}

bool InputEngine::appendLineToConfig(std::string line, std::string outfile)
{
	FILE *f = fopen(const_cast<char *>(outfile.c_str()),"a");
	if(!f)
		return false;
	fprintf(f, "%s\n", line.c_str());
	fclose(f);
	return true;
}

bool InputEngine::reloadConfig(std::string outfile)
{
	events.clear();
	loadMapping(outfile);
	return true;
}

bool InputEngine::updateConfigline(event_trigger_t *t)
{
	if(t->eventtype != ET_JoystickAxisAbs && t->eventtype != ET_JoystickSliderX && t->eventtype != ET_JoystickSliderY)
		return false;
	bool isSlider = (t->eventtype == ET_JoystickSliderX || t->eventtype == ET_JoystickSliderY);
	strcpy(t->configline, "");

	if(t->joystickAxisReverse && !strlen(t->configline))
		strcat(t->configline, "REVERSE");
	else if(t->joystickAxisReverse && strlen(t->configline))
		strcat(t->configline, "+REVERSE");

	// is this is a slider, ignore the rest
	if(isSlider) return true;

	if(t->joystickAxisRegion==1 && !strlen(t->configline))
		strcat(t->configline, "UPPER");
	else if(t->joystickAxisRegion==1 && strlen(t->configline))
		strcat(t->configline, "+UPPER");
	else if(t->joystickAxisRegion==-1 && !strlen(t->configline))
		strcat(t->configline, "LOWER");
	else if(t->joystickAxisRegion==-1 && strlen(t->configline))
		strcat(t->configline, "+LOWER");


	if(fabs(t->joystickAxisDeadzone-0.1) > 0.0001f)
	{
		char tmp[255]="";
		memset(tmp, 0, 255);
		sprintf(tmp, "DEADZONE=%0.2f", t->joystickAxisDeadzone);
		if(strlen(t->configline))
		{
			strcat(t->configline, "+");
			strcat(t->configline, tmp);
		}
		else
			strcat(t->configline, tmp);
	}
	if(fabs(1.0f - t->joystickAxisLinearity) > 0.01f)
	{
		char tmp[255]="";
		memset(tmp, 0, 255);
		sprintf(tmp, "LINEARITY=%0.2f", t->joystickAxisLinearity);
		if(strlen(t->configline))
		{
			strcat(t->configline, "+");
			strcat(t->configline, tmp);
		}
		else
			strcat(t->configline, tmp);
	}
	return true;
}

bool InputEngine::saveMapping(Ogre::String outfile, size_t hwnd, int joyNum)
{
	// -10 = all
	// -2  = keyboard
	// -3  = mouse
	// >0 joystick
	FILE *f = fopen(const_cast<char *>(outfile.c_str()),"w");
	if(!f)
		return false;
	std::map<int, std::vector<event_trigger_t> > controls = getEvents();
	std::map<int, std::vector<event_trigger_t> >::iterator mapIt;
	std::vector<event_trigger_t>::iterator vecIt;

	bool created=false;
	if(mInputManager && !captureMode && hwnd>0)
	{
		destroy();
		setup(hwnd, true, true);
		created=true;
	}
	if(!mInputManager && hwnd>0)
	{
		destroy();
		setup(hwnd, true, true);
		created=true;
	}
	if(mInputManager)
	{
		// some helpful information
		unsigned int v = mInputManager->getVersionNumber();
		fprintf(f, ";==== Input System Information Start\n");
		fprintf(f, ";OIS Version: %d.%d.%d\n",(v>>16), ((v>>8) & 0x000000FF), (v & 0x000000FF));
		fprintf(f, ";OIS Release Name: '%s'\n", mInputManager->getVersionName().c_str());
		fprintf(f, ";OIS Manager: %s\n", mInputManager->inputSystemName().c_str());
		fprintf(f, ";Total Keyboards: %d\n", mInputManager->getNumberOfDevices(OISKeyboard));
		fprintf(f, ";Total Mice: %d\n", mInputManager->getNumberOfDevices(OISMouse));
		fprintf(f, ";Total JoySticks: %d\n", mInputManager->getNumberOfDevices(OISJoyStick));
		OIS::DeviceList list = mInputManager->listFreeDevices();
		for(OIS::DeviceList::iterator i = list.begin(); i != list.end(); ++i )
			fprintf(f, "; OIS Device: %s Vendor: '%s'\n",mOISDeviceType[i->first], i->second.c_str());
		for(int i = 0; i < mInputManager->getNumberOfDevices(OISJoyStick); ++i)
		{
			if(joyNum != -1 && i != joyNum) continue;
			if(!mJoy[i]) continue;
			fprintf(f, ";*Joystick %d '%s'\n", i, mJoy[i]->vendor().c_str());
			if(mJoy[i]->getNumberOfComponents(OIS_Axis)>0)    fprintf(f, ";**Axes: %d\n", mJoy[i]->getNumberOfComponents(OIS_Axis));
			if(mJoy[i]->getNumberOfComponents(OIS_Slider)>0)  fprintf(f, ";**Sliders: %d\n", mJoy[i]->getNumberOfComponents(OIS_Slider));
			if(mJoy[i]->getNumberOfComponents(OIS_POV)>0)     fprintf(f, ";**POV/HATs: %d\n", mJoy[i]->getNumberOfComponents(OIS_POV));
			if(mJoy[i]->getNumberOfComponents(OIS_Button)>0)  fprintf(f, ";**Buttons: %d\n", mJoy[i]->getNumberOfComponents(OIS_Button));
			if(mJoy[i]->getNumberOfComponents(OIS_Vector3)>0) fprintf(f, ";**Vector3: %d\n", mJoy[i]->getNumberOfComponents(OIS_Vector3));
		}
		fprintf(f, ";==== Input System Information End\n");

		if(created)
			destroy();
	}

	int counter = 0;
	char curGroup[128] = "";
	for(mapIt = controls.begin(); mapIt != controls.end(); mapIt++)
	{
		std::vector<event_trigger_t> vec = mapIt->second;

		for(vecIt = vec.begin(); vecIt != vec.end(); vecIt++, counter++)
		{
			// filters
			if(vecIt->eventtype == ET_Keyboard && joyNum != -10 && joyNum != -2) continue;
			if((vecIt->eventtype == ET_MouseAxisX || vecIt->eventtype == ET_MouseAxisY || vecIt->eventtype == ET_MouseAxisZ) && joyNum != -10 && joyNum != -3) continue;
			if((vecIt->eventtype == ET_JoystickAxisAbs || vecIt->eventtype == ET_JoystickAxisRel || vecIt->eventtype == ET_JoystickButton || vecIt->eventtype == ET_JoystickPov || vecIt->eventtype == ET_JoystickSliderX || vecIt->eventtype == ET_JoystickSliderY) && joyNum>=0 && vecIt->joystickNumber != joyNum) continue;

			if(strcmp(vecIt->group, curGroup))
			{
				strncpy(curGroup, vecIt->group, 128);
				// group title:
				fprintf(f, "\n; %s\n", curGroup);
			}

			// no user comments for now!
			//if(vecIt->comments!="")
			//	fprintf(f, "%s", vecIt->comments.c_str());

			// print event name
			fprintf(f, "%-30s ", eventIDToName(mapIt->first).c_str());
			// print event type
			fprintf(f, "%-20s ", getEventTypeName(vecIt->eventtype).c_str());

			if(vecIt->eventtype == ET_Keyboard)
			{
				fprintf(f, "%s ", vecIt->configline);
			} else if(vecIt->eventtype == ET_JoystickAxisAbs || vecIt->eventtype == ET_JoystickAxisRel)
			{
				fprintf(f, "%d ", vecIt->joystickNumber);
				fprintf(f, "%d ", vecIt->joystickAxisNumber);
				fprintf(f, "%s ", vecIt->configline);
			} else if(vecIt->eventtype == ET_JoystickSliderX || vecIt->eventtype == ET_JoystickSliderY)
			{
				fprintf(f, "%d ", vecIt->joystickNumber);
				fprintf(f, "%d ", vecIt->joystickSliderNumber);
				fprintf(f, "%s ", vecIt->configline);
			} else if(vecIt->eventtype == ET_JoystickButton)
			{
				fprintf(f, "%d ", vecIt->joystickNumber);
				fprintf(f, "%d ", vecIt->joystickButtonNumber);
			} else if(vecIt->eventtype == ET_JoystickPov)
			{
				fprintf(f, "%d ", vecIt->joystickNumber);
			}
			// end this line
			fprintf(f, "\n");
		}
	}
	fclose(f);
	return true;
}

void InputEngine::completeMissingEvents()
{
	int i=0;
	while(i!=EV_MODE_LAST)
	{
		if(events.find(eventInfo[i].eventID) == events.end())
		{
#ifndef NOOGRE
			LogManager::getSingleton().logMessage("event mapping not existing, using default: " + eventInfo[i].name);
#endif
			// not existing, insert default
			processLine(const_cast<char*>(eventInfo[i].defaultKey.c_str()));
		}
		i++;
	}
}

bool InputEngine::loadMapping(Ogre::String outfile, bool append)
{
	char line[1025] = "";

	if(!append)
	{
		// clear everything
		resetKeys();
		events.clear();
	}

#ifndef NOOGRE
	LogManager::getSingleton().logMessage("Loading input mapping...");
	{
		DataStreamPtr ds = ResourceGroupManager::getSingleton().openResource(outfile, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		while (!ds->eof())
		{
			size_t size = 1024;
			if(ds->tell() + size >= ds->size())
				size = ds->size()-ds->tell();
			if(ds->tell() >= ds->size())
				break;
			size_t readnum = ds->readLine(line, size);
			if(readnum > 5)
				processLine(line);
		}
	}
#else
	FILE *f = fopen(outfile.c_str(), "r");
	if(!f)
		return false;
	while(fgets(line, 1024, f)!=NULL)
	{
		if(strnlen(line, 1024) > 5)
			processLine(line);
	}
	fclose(f);

#endif

	mappingLoaded = true;

#ifndef NOOGRE
	LogManager::getSingleton().logMessage("key map successfully loaded!");
#endif
	return true;
}

int InputEngine::resolveEventName(Ogre::String eventName)
{
	int i=0;
	while(i!=EV_MODE_LAST)
	{
		if(eventInfo[i].name == eventName)
			return eventInfo[i].eventID;
		i++;
	}
#ifndef NOOGRE
	LogManager::getSingleton().logMessage("unkown event (ignored): " + eventName);
#endif
	return -1;
}

Ogre::String InputEngine::eventIDToName(int eventID)
{
	int i=0;
	while(i!=EV_MODE_LAST)
	{
		if(eventInfo[i].eventID == eventID)
			return eventInfo[i].name;
		i++;
	}
	return "Unkown";
}

void InputEngine::initAllKeys()
{
	allkeys["0"] = KC_0;
	allkeys["1"] = KC_1;
	allkeys["2"] = KC_2;
	allkeys["3"] = KC_3;
	allkeys["4"] = KC_4;
	allkeys["5"] = KC_5;
	allkeys["6"] = KC_6;
	allkeys["7"] = KC_7;
	allkeys["8"] = KC_8;
	allkeys["9"] = KC_9;
	allkeys["A"] = KC_A ;
	allkeys["ABNT_C1"] = KC_ABNT_C1;
	allkeys["ABNT_C2"] = KC_ABNT_C2;
	allkeys["ADD"] = KC_ADD;
	allkeys["APOSTROPHE"] = KC_APOSTROPHE;
	allkeys["APPS"] = KC_APPS;
	allkeys["AT"] = KC_AT;
	allkeys["AX"] = KC_AX;
	allkeys["B"] = KC_B;
	allkeys["BACK"] = KC_BACK;
	allkeys["BACKSLASH"] = KC_BACKSLASH;
	allkeys["C"] = KC_C;
	allkeys["CALCULATOR"] = KC_CALCULATOR;
	allkeys["CAPITAL"] = KC_CAPITAL;
	allkeys["COLON"] = KC_COLON;
	allkeys["COMMA"] = KC_COMMA;
	allkeys["CONVERT"] = KC_CONVERT;
	allkeys["D"] = KC_D;
	allkeys["DECIMAL"] = KC_DECIMAL;
	allkeys["DELETE"] = KC_DELETE;
	allkeys["DIVIDE"] = KC_DIVIDE;
	allkeys["DOWN"] = KC_DOWN;
	allkeys["E"] = KC_E;
	allkeys["END"] = KC_END;
	allkeys["EQUALS"] = KC_EQUALS;
	allkeys["ESCAPE"] = KC_ESCAPE;
	allkeys["F"] = KC_F;
	allkeys["F1"] = KC_F1;
	allkeys["F10"] = KC_F10;
	allkeys["F11"] = KC_F11;
	allkeys["F12"] = KC_F12;
	allkeys["F13"] = KC_F13;
	allkeys["F14"] = KC_F14;
	allkeys["F15"] = KC_F15;
	allkeys["F2"] = KC_F2;
	allkeys["F3"] = KC_F3;
	allkeys["F4"] = KC_F4;
	allkeys["F5"] = KC_F5;
	allkeys["F6"] = KC_F6;
	allkeys["F7"] = KC_F7;
	allkeys["F8"] = KC_F8;
	allkeys["F9"] = KC_F9;
	allkeys["G"] = KC_G;
	allkeys["GRAVE"] = KC_GRAVE;
	allkeys["H"] = KC_H;
	allkeys["HOME"] = KC_HOME;
	allkeys["I"] = KC_I;
	allkeys["INSERT"] = KC_INSERT;
	allkeys["J"] = KC_J;
	allkeys["K"] = KC_K;
	allkeys["KANA"] = KC_KANA;
	allkeys["KANJI"] = KC_KANJI;
	allkeys["L"] = KC_L;
	allkeys["LBRACKET"] = KC_LBRACKET;
	allkeys["LCONTROL"] = KC_LCONTROL;
	allkeys["LEFT"] = KC_LEFT;
	allkeys["LMENU"] = KC_LMENU;
	allkeys["LSHIFT"] = KC_LSHIFT;
	allkeys["LWIN"] = KC_LWIN;
	allkeys["M"] = KC_M;
	allkeys["MAIL"] = KC_MAIL;
	allkeys["MEDIASELECT"] = KC_MEDIASELECT;
	allkeys["MEDIASTOP"] = KC_MEDIASTOP;
	allkeys["MINUS"] = KC_MINUS;
	allkeys["MULTIPLY"] = KC_MULTIPLY;
	allkeys["MUTE"] = KC_MUTE;
	allkeys["MYCOMPUTER"] = KC_MYCOMPUTER;
	allkeys["N"] = KC_N;
	allkeys["NEXTTRACK"] = KC_NEXTTRACK;
	allkeys["NOCONVERT"] = KC_NOCONVERT;
	allkeys["NUMLOCK"] = KC_NUMLOCK;
	allkeys["NUMPAD0"] = KC_NUMPAD0;
	allkeys["NUMPAD1"] = KC_NUMPAD1;
	allkeys["NUMPAD2"] = KC_NUMPAD2;
	allkeys["NUMPAD3"] = KC_NUMPAD3;
	allkeys["NUMPAD4"] = KC_NUMPAD4;
	allkeys["NUMPAD5"] = KC_NUMPAD5;
	allkeys["NUMPAD6"] = KC_NUMPAD6;
	allkeys["NUMPAD7"] = KC_NUMPAD7;
	allkeys["NUMPAD8"] = KC_NUMPAD8;
	allkeys["NUMPAD9"] = KC_NUMPAD9;
	allkeys["NUMPADCOMMA"] = KC_NUMPADCOMMA;
	allkeys["NUMPADENTER"] = KC_NUMPADENTER;
	allkeys["NUMPADEQUALS"] = KC_NUMPADEQUALS;
	allkeys["O"] = KC_O;
	allkeys["OEM_102"] = KC_OEM_102;
	allkeys["P"] = KC_P;
	allkeys["PAUSE"] = KC_PAUSE;
	allkeys["PERIOD"] = KC_PERIOD;
	allkeys["PGDOWN"] = KC_PGDOWN;
	allkeys["PGUP"] = KC_PGUP;
	allkeys["PLAYPAUSE"] = KC_PLAYPAUSE;
	allkeys["POWER"] = KC_POWER;
	allkeys["PREVTRACK"] = KC_PREVTRACK;
	allkeys["Q"] = KC_Q;
	allkeys["R"] = KC_R;
	allkeys["RBRACKET"] = KC_RBRACKET;
	allkeys["RCONTROL"] = KC_RCONTROL;
	allkeys["RETURN"] = KC_RETURN;
	allkeys["RIGHT"] = KC_RIGHT;
	allkeys["RMENU"] = KC_RMENU;
	allkeys["RSHIFT"] = KC_RSHIFT;
	allkeys["RWIN"] = KC_RWIN;
	allkeys["S"] = KC_S;
	allkeys["SCROLL"] = KC_SCROLL;
	allkeys["SEMICOLON"] = KC_SEMICOLON;
	allkeys["SLASH"] = KC_SLASH;
	allkeys["SLEEP"] = KC_SLEEP;
	allkeys["SPACE"] = KC_SPACE;
	allkeys["STOP"] = KC_STOP;
	allkeys["SUBTRACT"] = KC_SUBTRACT;
	allkeys["SYSRQ"] = KC_SYSRQ;
	allkeys["T"] = KC_T;
	allkeys["TAB"] = KC_TAB;
	allkeys["U"] = KC_U;
	//allkeys["UNASSIGNED"] = KC_UNASSIGNED;
	allkeys["UNDERLINE"] = KC_UNDERLINE;
	allkeys["UNLABELED"] = KC_UNLABELED;
	allkeys["UP"] = KC_UP;
	allkeys["V"] = KC_V;
	allkeys["VOLUMEDOWN"] = KC_VOLUMEDOWN;
	allkeys["VOLUMEUP"] = KC_VOLUMEUP;
	allkeys["W"] = KC_W;
	allkeys["WAKE"] = KC_WAKE;
	allkeys["WEBBACK"] = KC_WEBBACK;
	allkeys["WEBFAVORITES"] = KC_WEBFAVORITES;
	allkeys["WEBFORWARD"] = KC_WEBFORWARD;
	allkeys["WEBHOME"] = KC_WEBHOME;
	allkeys["WEBREFRESH"] = KC_WEBREFRESH;
	allkeys["WEBSEARCH"] = KC_WEBSEARCH;
	allkeys["WEBSTOP"] = KC_WEBSTOP;
	allkeys["X"] = KC_X;
	allkeys["Y"] = KC_Y;
	allkeys["YEN"] = KC_YEN;
	allkeys["Z"] = KC_Z;
}


