File InputContext.c

File List > engine > src > input > InputContext.c

Go to the documentation of this file

#include "InputContext.h"
#include <string.h>
#include "cJSON.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <GLFW/glfw3.h>
#include "FileHelpers.h"
#include "AssertLib.h"
#include "Log.h"
#include "StringKeyHashMap.h"
#include "cwalk.h"
#include "main.h"

static int gJoystick = -1;

struct HashMap gGLFWCodeKeyboardNameLUT;

int In_FindMouseButtonMapping(InputContext* context, const char* name)
{
    for (int i = 0; i < context->buttonMappings.MouseButtonMappings.size; i++)
    {
        if (strcmp(context->buttonMappings.MouseButtonMappings.arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return NULL_HANDLE;
}

int In_FindKeyboardButtonMapping(InputContext* context, const char* name)
{
    for (int i = 0; i < context->buttonMappings.KeyboardButtonMappings.size; i++)
    {
        if (strcmp(context->buttonMappings.KeyboardButtonMappings.arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return NULL_HANDLE;
}

int In_FindGamepadButtonMapping(InputContext* context, const char* name)
{
    for (int i = 0; i < context->buttonMappings.GamepadMappings.size; i++)
    {
        if (strcmp(context->buttonMappings.GamepadMappings.arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return NULL_HANDLE;
}

int In_FindMouseScrollButtonMapping(InputContext* context, const char* name)
{
    for (int i = 0; i < context->buttonMappings.MouseScrollButtonMappings.size; i++)
    {
        if (strcmp(context->buttonMappings.MouseScrollButtonMappings.arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return NULL_HANDLE;
}

int In_FindMouseAxisMapping(InputContext* context, const char* name)
{
    for (int i = 0; i < context->axisMappings.Mouse.size; i++)
    {
        if (strcmp(context->axisMappings.Mouse.arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return NULL_HANDLE;
}

int In_FindControllerAxisMapping(InputContext* context, const char* name)
{
    for (int i = 0; i < context->axisMappings.Controller.size; i++)
    {
        if (strcmp(context->axisMappings.Controller.arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return NULL_HANDLE;
}

int In_FindMouseScrollAxisMapping(InputContext* context, const char* name)
{
    for (int i = 0; i < context->axisMappings.MouseScroll.size; i++)
    {
        if (strcmp(context->axisMappings.MouseScroll.arr[i].name, name) == 0)
        {
            return i;
        }
    }
    return NULL_HANDLE;
}


struct AxisBinding In_FindAxisMapping(InputContext* context, const char* name)
{
    int handle = In_FindMouseAxisMapping(context, name);
    if (handle != NULL_HANDLE)
    {
        struct AxisBinding b = { MouseAxis, handle };
        return b;
    }
    handle = In_FindControllerAxisMapping(context, name);
    if (handle != NULL_HANDLE)
    {
        struct AxisBinding b = { GamePadAxis, handle };
        return b;
    }
    handle = In_FindMouseScrollAxisMapping(context, name);
    if (handle != NULL_HANDLE)
    {
        struct AxisBinding b = { MouseScrollAxis, handle };
        return b;
    }
    struct AxisBinding b = { UnknownAxis, NULL_HANDLE };
    return b;
}

struct ButtonBinding In_FindButtonMapping(InputContext* context, const char* name)
{
    int handle = In_FindMouseButtonMapping(context, name);
    if (handle != NULL_HANDLE)
    {
        struct ButtonBinding b = { MouseButton, handle };
        return b;
    }
    handle = In_FindGamepadButtonMapping(context, name);
    if (handle != NULL_HANDLE)
    {
        struct ButtonBinding b = { GamepadButton, handle };
        return b;
    }
    handle = In_FindKeyboardButtonMapping(context, name);
    if (handle != NULL_HANDLE)
    {
        struct ButtonBinding b = { KeyboardButton, handle };
        return b;
    }
    handle = In_FindMouseScrollButtonMapping(context, name);
    if (handle != NULL_HANDLE)
    {
        struct ButtonBinding b = { MouseScrollButton, handle };
        return b;
    }
    struct ButtonBinding b = { UnknownButton, NULL_HANDLE };
    return b;
}

float In_GetAxisValue(InputContext* context, struct AxisBinding binding)
{
    EASSERT(binding.index > -1);
    EASSERT(binding.type != UnknownAxis);
    switch (binding.type)
    {
    case MouseAxis:
        return context->axisMappings.Mouse.arr[binding.index].data.axisMapping.fCurrent;
        break;
    case GamePadAxis:
        return context->axisMappings.Controller.arr[binding.index].data.axisMapping.fCurrent;
    case MouseScrollAxis:
        return context->axisMappings.MouseScroll.arr[binding.index].data.axisMapping.fCurrent;
    }
    return 0.0f;
}

bool In_GetButtonValue(InputContext* context, struct ButtonBinding binding)
{
    EASSERT(binding.index > -1);
    EASSERT(binding.type != UnknownButton);
    switch (binding.type)
    {
    case MouseButton:
        return context->buttonMappings.MouseButtonMappings.arr[binding.index].data.ButtonMapping.bCurrent;
    case KeyboardButton:
        return context->buttonMappings.KeyboardButtonMappings.arr[binding.index].data.ButtonMapping.bCurrent;
    case GamepadButton:
        return context->buttonMappings.GamepadMappings.arr[binding.index].data.ButtonMapping.bCurrent;
    case MouseScrollButton:
        return context->buttonMappings.MouseScrollButtonMappings.arr[binding.index].data.ButtonMapping.bCurrent;
    }
    return false;
}

float In_GetMouseAxisValue(InputContext* context, HMouseAxisBinding hBinding)
{
    return (float)context->axisMappings.Mouse.arr[hBinding].data.axisMapping.fCurrent;
}

bool In_GetMouseButtonValue(InputContext* context, HMouseButtonBinding hBinding)
{
    return context->buttonMappings.MouseButtonMappings.arr[hBinding].data.ButtonMapping.bCurrent;
}

static bool TextEntryAllowedKeystroke(int key)
{
    return 
        (key >= GLFW_KEY_A && key <= GLFW_KEY_Z) ||
        (key >= GLFW_KEY_0 && key <= GLFW_KEY_9) ||
        key == GLFW_KEY_SPACE ||
        key == GLFW_KEY_APOSTROPHE ||
        key == GLFW_KEY_COMMA ||
        key == GLFW_KEY_MINUS ||
        key == GLFW_KEY_PERIOD ||
        key == GLFW_KEY_SLASH ||
        key == GLFW_KEY_SEMICOLON ||
        key == GLFW_KEY_EQUAL ||
        key == GLFW_KEY_RIGHT ||
        key == GLFW_KEY_LEFT ||
        key == GLFW_KEY_UP ||
        key == GLFW_KEY_DOWN ||
        key == GLFW_KEY_BACKSPACE;
}

static int Shifted(int c, bool capslock)
{
    // todo: do this properly for other keys besides 0-9
    if(c >= GLFW_KEY_0 && c <= GLFW_KEY_9)
    {
        int LUT[10] =
        {
            ')',
            '!',
            '"',
            '$',//'£', // £ causes warning, multi character
            '$',
            '%',
            '^',
            '&',
            '*',
            '(',
        };
        return LUT[c - GLFW_KEY_0];
    }
    else if(c >= GLFW_KEY_A && c <= GLFW_KEY_Z)
    {
        if(capslock)
        {
            return tolower(c);  
        }
        else
        {
            return c;
        }
    }
    else
    {
        return c;
    }

}

static void DoTextInput(InputContext* context, int key, int scancode, int action, int mods)
{

    int ascii = 0;

    if(key == GLFW_KEY_CAPS_LOCK)
    {
        switch(action)
        {
        case GLFW_PRESS:
            EASSERT(!context->textInput.capslockModifier);
            context->textInput.capslockModifier = true;
            break;
        case GLFW_RELEASE:
            EASSERT(context->textInput.capslockModifier);
            context->textInput.capslockModifier = false;
            break;
        }
    }
    else if(key == GLFW_KEY_LEFT_SHIFT)
    {
        switch(action)
        {
        case GLFW_PRESS:
            EASSERT(!context->textInput.shiftModifier);
            context->textInput.shiftModifier = true;
            break;
        case GLFW_RELEASE:
            EASSERT(context->textInput.shiftModifier);
            context->textInput.shiftModifier = false;
            break;
        }
    }
    else if (action == GLFW_PRESS)
    {
        if(context->textInput.shiftModifier)
        {
            ascii = Shifted((char)key, context->textInput.capslockModifier);
        }
        else if(!context->textInput.capslockModifier && (key >= GLFW_KEY_A && key <= GLFW_KEY_Z))
        {
            ascii = tolower(key);
        }
        else
        {
            ascii = key;
        }
        context->textInput.keystrokes[context->textInput.nKeystrokesThisFrame++] = ascii;
    }

}

void In_RecieveKeyboardKey(InputContext* context, int key, int scancode, int action, int mods)
{
    DoTextInput(context, key, scancode, action, mods);
    for (int i = 0; i < context->buttonMappings.KeyboardButtonMappings.size; i++)
    {
        InputMapping* pMapping = &context->buttonMappings.KeyboardButtonMappings.arr[i];
        if (context->buttonMappings.KeyboardButtonMappings.ActiveMask & (1 << i))
        {
            if (pMapping->data.ButtonMapping.data.keyboard.keyboadCode == key)
            {
                if (action == GLFW_PRESS)
                {
                    pMapping->data.ButtonMapping.bCurrent = true;
                    pMapping->data.ButtonMapping.bPressThisFrame = true;
                }
                else if (action == GLFW_RELEASE)
                {
                    pMapping->data.ButtonMapping.bCurrent = false;
                    pMapping->data.ButtonMapping.bReleaseThisFrame = true;
                }
            }
        }
    }
}

void In_RecieveMouseMove(InputContext* context, double xposIn, double yposIn)
{
    for (int i = 0; i < context->axisMappings.Mouse.size; i++)
    {
        InputMapping* pMapping = &context->axisMappings.Mouse.arr[i];
        if (context->axisMappings.Mouse.ActiveMask & (1 << i))
        {
            if (pMapping->data.axisMapping.data.mouse.axis == Axis_X)
            {
                pMapping->data.axisMapping.fCurrent = xposIn;
            }
            else if (pMapping->data.axisMapping.data.mouse.axis == Axis_Y)
            {
                pMapping->data.axisMapping.fCurrent = yposIn;
            }
        }
    }
}

void In_RecieveMouseButton(InputContext* context, int button, int action, int mods)
{
    for (int i = 0; i < context->buttonMappings.MouseButtonMappings.size; i++)
    {
        InputMapping* pMapping = &context->buttonMappings.MouseButtonMappings.arr[i];
        if (context->buttonMappings.MouseButtonMappings.ActiveMask & (1 << i))
        {
            if (pMapping->data.ButtonMapping.data.mouseBtn.button == button)
            {
                if (action == GLFW_PRESS)
                {
                    static int dCounter = 0;
                    pMapping->data.ButtonMapping.bCurrent = true;
                    pMapping->data.ButtonMapping.bPressThisFrame = true;
                }
                else if (action == GLFW_RELEASE)
                {
                    pMapping->data.ButtonMapping.bCurrent = false;
                    pMapping->data.ButtonMapping.bReleaseThisFrame = true;
                }
            }
        }
    }
}

void In_FramebufferResize(InputContext* context, int width, int height)
{
    context->screenH = height;
    context->screenW = width;
}

void In_RecieveScroll(InputContext* context, double xoffset, double yoffset)
{
    for (int i = 0; i < context->axisMappings.MouseScroll.size; i++)
    {
        InputMapping* pMapping = &context->axisMappings.MouseScroll.arr[i];
        if (context->axisMappings.MouseScroll.ActiveMask & (1 << i))
        {
            if (pMapping->data.axisMapping.data.mouseScroll.axis == Axis_X)
            {
                pMapping->data.axisMapping.fCurrent = xoffset;
            }
            else if (pMapping->data.axisMapping.data.mouseScroll.axis == Axis_Y)
            {
                pMapping->data.axisMapping.fCurrent = yoffset;
            }
        }
    }
    for (int i = 0; i < context->buttonMappings.MouseScrollButtonMappings.size; i++)
    {
        InputMapping* pMapping = &context->buttonMappings.MouseScrollButtonMappings.arr[i];
        if (context->buttonMappings.MouseScrollButtonMappings.ActiveMask & (1 << i))
        {
            switch (pMapping->data.ButtonMapping.data.mouseScrollButton.axis)
            {
            case Axis_X:
                if (pMapping->data.ButtonMapping.data.mouseScrollButton.dir == Axis_Pos && xoffset > 0)
                {
                    pMapping->data.ButtonMapping.bCurrent = true;
                    pMapping->data.ButtonMapping.bPressThisFrame = true;
                    pMapping->data.ButtonMapping.bReleaseThisFrame = true;
                }
                if (pMapping->data.ButtonMapping.data.mouseScrollButton.dir == Axis_Neg && xoffset < 0)
                {
                    pMapping->data.ButtonMapping.bCurrent = true;
                    pMapping->data.ButtonMapping.bPressThisFrame = true;
                    pMapping->data.ButtonMapping.bReleaseThisFrame = true;
                }
                break;
            case Axis_Y:
                if (pMapping->data.ButtonMapping.data.mouseScrollButton.dir == Axis_Pos && yoffset > 0)
                {
                    pMapping->data.ButtonMapping.bCurrent = true;
                    pMapping->data.ButtonMapping.bPressThisFrame = true;
                    pMapping->data.ButtonMapping.bReleaseThisFrame = true;
                }
                if (pMapping->data.ButtonMapping.data.mouseScrollButton.dir == Axis_Neg && yoffset < 0)
                {
                    pMapping->data.ButtonMapping.bCurrent = true;
                    pMapping->data.ButtonMapping.bPressThisFrame = true;
                    pMapping->data.ButtonMapping.bReleaseThisFrame = true;
                }
                break;
            }
        }
    }
}

void In_SetControllerPresent(int controllerNo)
{
    gJoystick = controllerNo;
}

void In_EndFrame(InputContext* context)
{
    context->textInput.nKeystrokesThisFrame = 0;

    /*
        Reset these - mappings where the mouse scroll wheel is behaving as a button.
        Unlike other buttons this one isn't pressed and released, its an instantaneous event that should be handled once
    */
    for (int i = 0; i < context->buttonMappings.MouseScrollButtonMappings.size; i++)
    {
        InputMapping* pMapping = &context->buttonMappings.MouseScrollButtonMappings.arr[i];
        pMapping->data.ButtonMapping.bCurrent = false;
        pMapping->data.ButtonMapping.bPressThisFrame = false;
        pMapping->data.ButtonMapping.bReleaseThisFrame = false;
    }

    for (int i = 0; i < context->buttonMappings.KeyboardButtonMappings.size; i++)
    {
        InputMapping* pMapping = &context->buttonMappings.KeyboardButtonMappings.arr[i];
        pMapping->data.ButtonMapping.bPressThisFrame = false;
        pMapping->data.ButtonMapping.bReleaseThisFrame = false;
    }

    for (int i = 0; i < context->buttonMappings.MouseButtonMappings.size; i++)
    {
        InputMapping* pMapping = &context->buttonMappings.MouseButtonMappings.arr[i];
        pMapping->data.ButtonMapping.bPressThisFrame = false;
        pMapping->data.ButtonMapping.bReleaseThisFrame = false;
    }

    for (int i = 0; i < context->buttonMappings.GamepadMappings.size; i++)
    {
        InputMapping* pMapping = &context->buttonMappings.GamepadMappings.arr[i];
        pMapping->data.ButtonMapping.bPressThisFrame = false;
        pMapping->data.ButtonMapping.bReleaseThisFrame = false;
    }

}

typedef void(*SetButtonCodeCallback)(InputMapping*, int);

static void AddChildButtonStructs(cJSON* parent, InputMappingArray* outMappings, SetButtonCodeCallback callback, ButtonSubType btnSubType)
{
    while (parent)
    {
        const char* name = parent->child->string;
        int val = -1;
        if(parent->child->type == cJSON_Number)
        {
            val = parent->child->valueint;
        }
        else if(parent->child->type == cJSON_String)
        {
            int* pVal = NULL;
            pVal = HashmapSearch(&gGLFWCodeKeyboardNameLUT, parent->child->valuestring);
            if(!pVal)
            {
                Log_Error("Invalid button value: '%s'", parent->child->valuestring);
                continue;
            }
            else
            {
                val = *pVal;
            }
        }

        InputMapping mapping;
        size_t  allocSize = strlen(name) + 1;
        mapping.name = malloc(allocSize);
        memset(mapping.name, 0, allocSize);
        strcpy(mapping.name, name);
        mapping.type = Button;
        mapping.data.ButtonMapping.type = btnSubType;
        mapping.data.ButtonMapping.bCurrent = false;
        mapping.data.ButtonMapping.bPressThisFrame = false;
        mapping.data.ButtonMapping.bReleaseThisFrame = false;

        callback(&mapping, val);
        outMappings->arr[outMappings->size++] = mapping;
        parent = parent->next;
    }
}

static void SetKeyboardCode(InputMapping* mapping, int code) { mapping->data.ButtonMapping.data.keyboard.keyboadCode = code; }
static void SetMouseBtnCode(InputMapping* mapping, int code) { mapping->data.ButtonMapping.data.mouseBtn.button = code; }
static void SetGamepadBtnCode(InputMapping* mapping, int code) { mapping->data.ButtonMapping.data.gamepadBtn.button = code; }

static void SetMouseScrollBtnCode(InputMapping* mapping, int code) 
{
    /*
        X Axis + : 3
        X Axis - : 1
        Y Axis + : 2
        Y Axis - : 0
    */
    if (code & 1)
    {
        mapping->data.ButtonMapping.data.mouseScrollButton.axis = Axis_X;
    }
    else
    {
        mapping->data.ButtonMapping.data.mouseScrollButton.axis = Axis_Y;
    }

    if (code & 2)
    {
        mapping->data.ButtonMapping.data.mouseScrollButton.dir = Axis_Pos;
    }
    else
    {
        mapping->data.ButtonMapping.data.mouseScrollButton.dir = Axis_Neg;
    }
}

static void AddMouseAxisMappingsStructs(cJSON* parent, InputContext* ctx)
{
    while (parent)
    {
        InputMapping mapping;
        memset(&mapping, 0, sizeof(InputMapping));

        cJSON* child = parent->child;
        const char* name = child->string;
        mapping.name = malloc(strlen(name) + 1);
        strcpy(mapping.name, name);
        mapping.type = Axis;
        //strcpy(mapping.name, name);
        mapping.data.axisMapping.type = MouseAxis;
        cJSON* props = child->child;
        while (props)
        {
            if (strcmp("axis", props->string) == 0)
            {
                if (strcmp("x", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.mouse.axis = Axis_X;
                }
                else if (strcmp("y", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.mouse.axis = Axis_Y;
                }
            }
            props = props->next;
        }
        parent = parent->next;
        ctx->axisMappings.Mouse.arr[ctx->axisMappings.Mouse.size++] = mapping;
    }
}

static void AddScrollAxisMappingsStructs(cJSON* parent, InputContext* ctx)
{
    while (parent)
    {
        InputMapping mapping;
        memset(&mapping, 0, sizeof(InputMapping));

        cJSON* child = parent->child;
        const char* name = child->string;
        mapping.name = malloc(strlen(name) + 1);
        strcpy(mapping.name, name);
        mapping.type = Axis;
        //strcpy(mapping.name, name);
        mapping.data.axisMapping.type = MouseScrollAxis;
        cJSON* props = child->child;
        while (props)
        {
            if (strcmp("axis", props->string) == 0)
            {
                if (strcmp("x", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.mouseScroll.axis = Axis_X;
                }
                else if (strcmp("y", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.mouseScroll.axis = Axis_Y;
                }
            }
            props = props->next;
        }
        parent = parent->next;
        ctx->axisMappings.MouseScroll.arr[ctx->axisMappings.MouseScroll.size++] = mapping;
    }
}

static void AddGamepadAxisMappingsStructs(cJSON* parent, InputContext* ctx)
{
    while (parent)
    {
        InputMapping mapping;
        memset(&mapping, 0, sizeof(InputMapping));

        cJSON* child = parent->child;
        const char* name = child->string;
        mapping.name = malloc(strlen(name) + 1);
        strcpy(mapping.name, name);
        mapping.type = Axis;
        //strcpy(mapping.name, name);
        mapping.data.axisMapping.type = GamePadAxis;
        cJSON* props = child->child;
        while (props)
        {
            if (strcmp("axis", props->string) == 0)
            {
                if (strcmp("x", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.controller.axis = Axis_X;
                }
                else if (strcmp("y", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.controller.axis = Axis_Y;
                }
            }
            else if (strcmp("stick", props->string) == 0)
            {
                if (strcmp("lstick", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.controller.type = gpAxis_LStick;
                }
                else if (strcmp("rstick", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.controller.type = gpAxis_RStick;
                }
                else if (strcmp("lTrigger", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.controller.type = gpAxis_LT;
                }
                else if (strcmp("rTrigger", props->valuestring) == 0)
                {
                    mapping.data.axisMapping.data.controller.type = gpAxis_RT;
                }

            }
            props = props->next;
        }
        parent = parent->next;
        ctx->axisMappings.Controller.arr[ctx->axisMappings.Controller.size++] = mapping;
    }
}

void LoadGLFWKeyboardInputLUT()
{
    // generated by GenerateGLFWKeyboardHashmap.py
    HashmapInit(&gGLFWCodeKeyboardNameLUT, 256, sizeof(int));
    int v = - 1;
    v = -1;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Unknown", &v);
    v = 32;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Space", &v);
    v = 39;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Apostrophe", &v);
    v = 44;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Comma", &v);
    v = 45;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Minus", &v);
    v = 46;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Period", &v);
    v = 47;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Slash", &v);
    v = 48;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num0", &v);
    v = 49;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num1", &v);
    v = 50;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num2", &v);
    v = 51;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num3", &v);
    v = 52;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num4", &v);
    v = 53;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num5", &v);
    v = 54;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num6", &v);
    v = 55;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num7", &v);
    v = 56;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num8", &v);
    v = 57;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Num9", &v);
    v = 59;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Semicolon", &v);
    v = 61;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Equal", &v);
    v = 65;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "A", &v);
    v = 66;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "B", &v);
    v = 67;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "C", &v);
    v = 68;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "D", &v);
    v = 69;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "E", &v);
    v = 70;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F", &v);
    v = 71;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "G", &v);
    v = 72;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "H", &v);
    v = 73;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "I", &v);
    v = 74;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "J", &v);
    v = 75;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "K", &v);
    v = 76;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "L", &v);
    v = 77;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "M", &v);
    v = 78;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "N", &v);
    v = 79;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "O", &v);
    v = 80;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "P", &v);
    v = 81;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Q", &v);
    v = 82;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "R", &v);
    v = 83;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "S", &v);
    v = 84;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "T", &v);
    v = 85;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "U", &v);
    v = 86;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "V", &v);
    v = 87;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "W", &v);
    v = 88;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "X", &v);
    v = 89;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Y", &v);
    v = 90;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Z", &v);
    v = 91;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "LeftBracket", &v);
    v = 92;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Backslash", &v);
    v = 93;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "RightBracket", &v);
    v = 96;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "GraveAccent", &v);
    v = 161;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "World1", &v);
    v = 162;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "World2", &v);
    v = 256;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Escape", &v);
    v = 257;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Enter", &v);
    v = 258;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Tab", &v);
    v = 259;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Backspace", &v);
    v = 260;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Insert", &v);
    v = 261;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Delete", &v);
    v = 262;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Right", &v);
    v = 263;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Left", &v);
    v = 264;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Down", &v);
    v = 265;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Up", &v);
    v = 266;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "PageUp", &v);
    v = 267;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "PageDown", &v);
    v = 268;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Home", &v);
    v = 269;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "End", &v);
    v = 280;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "CapsLock", &v);
    v = 281;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "ScrollLock", &v);
    v = 282;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "NumLock", &v);
    v = 283;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "PrintScreen", &v);
    v = 284;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Pause", &v);
    v = 290;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F1", &v);
    v = 291;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F2", &v);
    v = 292;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F3", &v);
    v = 293;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F4", &v);
    v = 294;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F5", &v);
    v = 295;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F6", &v);
    v = 296;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F7", &v);
    v = 297;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F8", &v);
    v = 298;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F9", &v);
    v = 299;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F10", &v);
    v = 300;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F11", &v);
    v = 301;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F12", &v);
    v = 302;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F13", &v);
    v = 303;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F14", &v);
    v = 304;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F15", &v);
    v = 305;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F16", &v);
    v = 306;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F17", &v);
    v = 307;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F18", &v);
    v = 308;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F19", &v);
    v = 309;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F20", &v);
    v = 310;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F21", &v);
    v = 311;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F22", &v);
    v = 312;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F23", &v);
    v = 313;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F24", &v);
    v = 314;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "F25", &v);
    v = 320;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad0", &v);
    v = 321;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad1", &v);
    v = 322;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad2", &v);
    v = 323;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad3", &v);
    v = 324;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad4", &v);
    v = 325;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad5", &v);
    v = 326;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad6", &v);
    v = 327;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad7", &v);
    v = 328;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad8", &v);
    v = 329;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Keypad9", &v);
    v = 330;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "KeypadDecimal", &v);
    v = 331;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "KeypadDivide", &v);
    v = 332;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "KeypadMultiply", &v);
    v = 333;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "KeypadSubtract", &v);
    v = 334;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "KeypadAdd", &v);
    v = 335;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "KeypadEnter", &v);
    v = 336;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "KeypadEqual", &v);
    v = 340;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "LeftShift", &v);
    v = 341;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "LeftControl", &v);
    v = 342;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "LeftAlt", &v);
    v = 343;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "LeftSuper", &v);
    v = 344;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "RightShift", &v);
    v = 345;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "RightControl", &v);
    v = 346;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "RightAlt", &v);
    v = 347;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "RightSuper", &v);
    v = 348;
    HashmapInsert(&gGLFWCodeKeyboardNameLUT, "Menu", &v);
}

InputContext In_InitInputContext()
{
    LoadGLFWKeyboardInputLUT();
#define ERROR(test, str) if(!test) {Log_Error("In_InitInputContext %s", str); InputContext v; memset(&v, 0, sizeof(InputContext)); return v;} 
    InputContext ctx;
    memset(&ctx, 0, sizeof(InputContext));

    char buf[256];
    cwk_path_join(gCmdArgs.configDir, "Keymap.json", buf, 256);

    int size = 0;
    char* data = LoadFile(buf, &size);
    ERROR(data, "can't load data");
    cJSON* json = cJSON_ParseWithLength(data, size);
    ERROR(json, "can't parse json");
    cJSON* buttons = cJSON_GetObjectItem(json, "Buttons");
    ERROR(buttons, "json child 'Buttons' not found.");


    cJSON* keyboard = cJSON_GetObjectItem(buttons, "Keyboard");
    ERROR(keyboard, "json child 'Buttons.Keyboard' not found.");
    cJSON* keyboardKeyMap = keyboard->child;
    AddChildButtonStructs(keyboardKeyMap, &ctx.buttonMappings.KeyboardButtonMappings, &SetKeyboardCode, KeyboardButton);

    cJSON* mouseBtn = cJSON_GetObjectItem(buttons, "Mouse");
    ERROR(mouseBtn, "mouseBtn");
    cJSON* mouseBtnMap = mouseBtn->child;
    AddChildButtonStructs(mouseBtnMap, &ctx.buttonMappings.MouseButtonMappings, &SetMouseBtnCode, MouseButton);

    cJSON* mouseScrollBtn = cJSON_GetObjectItem(buttons, "MouseScroll");
    ERROR(mouseScrollBtn, "MouseScroll");
    cJSON* mouseScrollBtnMap = mouseScrollBtn->child;
    AddChildButtonStructs(mouseScrollBtnMap, &ctx.buttonMappings.MouseScrollButtonMappings, &SetMouseScrollBtnCode, MouseScrollButton);

    cJSON* gamepadBtn = cJSON_GetObjectItem(buttons, "GamePad");
    ERROR(gamepadBtn, "GamePad");
    cJSON* gamepadBtnMap = gamepadBtn->child;
    AddChildButtonStructs(gamepadBtnMap, &ctx.buttonMappings.GamepadMappings, &SetGamepadBtnCode, GamepadButton);

    cJSON* axes = cJSON_GetObjectItem(json, "Axes");
    ERROR(axes, "json child 'Axes' not found.");

    cJSON* mouseAxes = cJSON_GetObjectItem(axes, "Mouse");
    ERROR(mouseAxes, "json child 'Axes.Mouse' not found.");
    cJSON* parent = mouseAxes->child;
    AddMouseAxisMappingsStructs(parent, &ctx);

    cJSON* gamepadAxis = cJSON_GetObjectItem(axes, "GamePad");
    ERROR(gamepadAxis, "json child 'Axes.GamePad' not found.");
    parent = gamepadAxis->child;
    AddGamepadAxisMappingsStructs(parent, &ctx);

    cJSON* mouseScroll = cJSON_GetObjectItem(axes, "MouseScroll");
    ERROR(mouseScroll, "json child 'Axes.MouseScroll' not found.");
    parent = mouseScroll->child;
    AddScrollAxisMappingsStructs(parent, &ctx);

    // HACK BEGIN - to be done some other better way in future
    ctx.axisMappings.Mouse.ActiveMask |= 1;
    ctx.axisMappings.Mouse.ActiveMask |= 2;
    ctx.buttonMappings.MouseButtonMappings.ActiveMask |= 3;
    // HACK END

    cJSON_Delete(json);
    free(data);
    return ctx;

#undef ERROR
}


void In_GetMask(struct ActiveInputBindingsMask* pOutMask, InputContext* pCtx)
{
    pOutMask->MouseButtonMappings = pCtx->buttonMappings.MouseButtonMappings.ActiveMask;
    pOutMask->KeyboardButtonMappings = pCtx->buttonMappings.KeyboardButtonMappings.ActiveMask;
    pOutMask->GamepadButtonMappings = pCtx->buttonMappings.GamepadMappings.ActiveMask;
    pOutMask->MouseScrollButtonMappings = pCtx->buttonMappings.MouseScrollButtonMappings.ActiveMask;

    pOutMask->MouseAxisMappings = pCtx->axisMappings.Mouse.ActiveMask;
    pOutMask->ControllerAxisMappings = pCtx->axisMappings.Controller.ActiveMask;
    pOutMask->MouseScrollAxisMappings = pCtx->axisMappings.MouseScroll.ActiveMask;
}

void In_SetMask(struct ActiveInputBindingsMask* mask, InputContext* pCtx)
{
    pCtx->buttonMappings.MouseButtonMappings.ActiveMask = mask->MouseButtonMappings;
    pCtx->buttonMappings.KeyboardButtonMappings.ActiveMask = mask->KeyboardButtonMappings;
    pCtx->buttonMappings.GamepadMappings.ActiveMask = mask->GamepadButtonMappings;
    pCtx->buttonMappings.MouseScrollButtonMappings.ActiveMask = mask->MouseScrollButtonMappings;

    pCtx->axisMappings.Mouse.ActiveMask = mask->MouseAxisMappings;
    pCtx->axisMappings.Controller.ActiveMask = mask->ControllerAxisMappings;
    pCtx->axisMappings.MouseScroll.ActiveMask = mask->MouseScrollAxisMappings;
}

void In_ActivateButtonBinding(struct ButtonBinding binding, struct ActiveInputBindingsMask* pMask)
{
    EASSERT(binding.index <= 63);
    switch (binding.type)
    {
    case MouseButton:
        pMask->MouseButtonMappings |= (1 << binding.index);
        break;
    case KeyboardButton:
        pMask->KeyboardButtonMappings |= (1 << binding.index);
        break;
    case GamepadButton:
        pMask->GamepadButtonMappings |= (1 << binding.index);
        break;
    case MouseScrollButton:
        pMask->MouseScrollButtonMappings |= (1 << binding.index);
        break;
    }
}

void In_ActivateAxisBinding(struct AxisBinding binding, struct ActiveInputBindingsMask* pMask)
{
    EASSERT(binding.index <= 63);
    switch (binding.type)
    {
    case MouseAxis:
        pMask->MouseAxisMappings |= (1 << binding.index);
        break;
    case GamePadAxis:
        pMask->ControllerAxisMappings |= (1 << binding.index);
        break;
    case MouseScrollAxis:
        pMask->MouseScrollAxisMappings |= (1 << binding.index);
        break;
    }
}

void In_DeactivateButtonBinding(struct ButtonBinding binding, struct ActiveInputBindingsMask* pMask)
{
        EASSERT(binding.index <= 63);
    switch (binding.type)
    {
    case MouseButton:
        pMask->MouseButtonMappings &= ~(1 << binding.index);
        break;
    case KeyboardButton:
        pMask->KeyboardButtonMappings &= ~(1 << binding.index);
        break;
    case GamepadButton:
        pMask->GamepadButtonMappings &= ~(1 << binding.index);
        break;
    case MouseScrollButton:
        pMask->MouseScrollButtonMappings &= ~(1 << binding.index);
        break;
    }

}

void In_DeactivateAxisBinding(struct AxisBinding binding, struct ActiveInputBindingsMask* pMask)
{
    EASSERT(binding.index <= 63);
    switch (binding.type)
    {
    case MouseAxis:
        pMask->MouseAxisMappings &= ~(1 << binding.index);
        break;
    case GamePadAxis:
        pMask->ControllerAxisMappings &= ~(1 << binding.index);
        break;
    case MouseScrollAxis:
        pMask->MouseScrollAxisMappings &= ~(1 << binding.index);
        break;
    }
}


bool In_GetButtonPressThisFrame(InputContext* context, struct ButtonBinding binding)
{
    EASSERT(binding.index > -1);
    EASSERT(binding.type != UnknownButton);
    switch (binding.type)
    {
    case MouseButton:
        return context->buttonMappings.MouseButtonMappings.arr[binding.index].data.ButtonMapping.bPressThisFrame;
    case KeyboardButton:
        return context->buttonMappings.KeyboardButtonMappings.arr[binding.index].data.ButtonMapping.bPressThisFrame;
    case GamepadButton:
        return context->buttonMappings.GamepadMappings.arr[binding.index].data.ButtonMapping.bPressThisFrame;
    case MouseScrollButton:
        return context->buttonMappings.MouseScrollButtonMappings.arr[binding.index].data.ButtonMapping.bPressThisFrame;
    }
    return false;
}

bool In_GetButtonReleaseThisFrame(InputContext* context, struct ButtonBinding binding)
{
    EASSERT(binding.index > -1);
    EASSERT(binding.type != UnknownButton);
    switch (binding.type)
    {
    case MouseButton:
        return context->buttonMappings.MouseButtonMappings.arr[binding.index].data.ButtonMapping.bReleaseThisFrame;
    case KeyboardButton:
        return context->buttonMappings.KeyboardButtonMappings.arr[binding.index].data.ButtonMapping.bReleaseThisFrame;
    case GamepadButton:
        return context->buttonMappings.GamepadMappings.arr[binding.index].data.ButtonMapping.bReleaseThisFrame;
    case MouseScrollButton:
        return context->buttonMappings.MouseScrollButtonMappings.arr[binding.index].data.ButtonMapping.bReleaseThisFrame;
    }
    return false;
}