//================================================================
// Platform independent input-handler
//
// AUTHOR:  Gabor Nagy
// DATE:    2024-Feb-03 19:55:53
//
// Copyright (C) 1996-2026 by Gabor Nagy. All rights reserved.
//================================================================
#ifndef _EInput_h
#define _EInput_h


#include <EMalloc.h>
#include <ELists.h>
#include <EParam.h>

#ifdef EX11
#define XK_MISCELLANY
#include <X11/keysymdef.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Xfuncproto.h>

#ifdef XT_BC
#include <X11/Xos.h>  // For R4 compatibility
#else
#include <X11/Xosdefs.h>
#endif
#endif // EX11

#ifndef _XeTypes_h
#include <Xe/XeTypes.h>
#endif


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif


enum
{
	EKeyINDEX_UP = 256,
	EKeyINDEX_DOWN,
	EKeyINDEX_LEFT,
	EKeyINDEX_RIGHT,
	EKeyINDEX_F1,
	EKeyINDEX_F2,
	EKeyINDEX_F3,
	EKeyINDEX_F4,
	EKeyINDEX_F5,
	EKeyINDEX_F6,
	EKeyINDEX_F7,
	EKeyINDEX_F8,
	EKeyINDEX_F9,
	EKeyINDEX_F10,
	EKeyINDEX_F11,
	EKeyINDEX_F12,
	EKeyINDEX_F13,
	EKeyINDEX_F14,
	EKeyINDEX_F15,
	EKeyINDEX_F16,
	EKeyINDEX_BACKSPACE,
	EKeyINDEX_TAB,
	EKeyINDEX_RETURN,
	EKeyINDEX_INSERT,
	EKeyINDEX_DELETE,
	EKeyINDEX_HOME,
	EKeyINDEX_END,
	EKeyINDEX_BEGIN,
	EKeyINDEX_PAGE_UP,
	EKeyINDEX_PAGE_DOWN,
	EKeyINDEX_ESCAPE
};


#define	EMAX_NUM_OF_KEYS_IN_TABLE  (EKeyINDEX_ESCAPE + 1)


// Key event priorities
//
enum
{
	EKeyPRIORITY_LOW = 0,
	EKeyPRIORITY_INTERNAL,
};


enum
{
	EKeyOK = 0,
	EKeyError
};

// Key events
//
enum
{
	EKeyPRESS = 1,
	EKeyRELEASE,
	EKeyOVERRIDE    // Hot-key was overwritten by an application-internal function
};


typedef void  (*EKeyCallbackFunc)(const EKeyCode PKey, const EKeyModifiers PModifiers, const int PKeyEventType,  EPointer PClientData);


typedef struct
{
	char*             Name;       // Name of action
	EKeyModifiers     Modifiers;
	char              Priority;

	EKeyCallbackFunc  Callback;
	EPointer          ClientData;
} EKeyEntry;

typedef struct
{
	EList(, EKeyEntry, Entries);
} EKeyRec;


#ifdef EX11
//#define EKeyF1   XK_F1
#define EKeyF1   XK_Help
#define EKeyF2   XK_F2
#define EKeyF3   XK_F3
#define EKeyF4   XK_F4
#define EKeyF5   XK_F5
#define EKeyF6   XK_F6
#define EKeyF7   XK_F7
#define EKeyF8   XK_F8
#define EKeyF9   XK_F9
#define EKeyF10  XK_F10
#define EKeyF11  XK_F11
#define EKeyF12  XK_F12
#define EKeyF13  XK_F13
#define EKeyF14  XK_F14
#define EKeyF15  XK_F15
#define EKeyF16  XK_F16

#define EKeyBACKSPACE    XK_BackSpace  // Back space, back char
#define EKeyTAB          XK_Tab
#define EKeyLINEFEED     XK_Linefeed   // Linefeed, LF
#define EKeyCLEAR        XK_Clear
#define EKeyRETURN       XK_Return     // Return, enter
#define EKeyPAUSE        XK_Pause      // Pause, hold
#define EKeySCROLL_LOCK  XK_Scroll_Lock
#define EKeySYS_REQ      XK_Sys_Req
#define EKeyESCAPE       XK_Cancel
#define EKeyINSERT       XK_Insert
#define EKeyDELETE       XK_Delete     // Delete, rubout

#define EKeyHOME         XK_Home
#define EKeyLEFT         XK_Left       // Move left, left arrow
#define EKeyUP           XK_Up         // Move up, up arrow
#define EKeyRIGHT        XK_Right      // Move right, right arrow
#define EKeyDOWN         XK_Down       // Move down, down arrow
#define EKeyPRIOR        XK_Prior      // Prior, previous
#define EKeyPAGE_UP      XK_Page_Up
#define EKeyNEXT         XK_Next       // Next
#define EKeyPAGE_DOWN    XK_Page_Down
#define EKeyEND          XK_End        // EOL
#define EKeyBEGIN        XK_Begin      // BOL

// Misc Functions
//
#define EKeyNUM_LOCK     XK_Num_Lock
#define EKeyMENU         XK_Menu


#define EKeySHIFT_L      XK_Shift_L     // Left shift
#define EKeySHIFT_R      XK_Shift_R     // Right shift
#define EKeyCONTROL_L    XK_Control_L   // Left control
#define EKeyCONTROL_R    XK_Control_R   // Right control
#define EKeyCAPS_LOCK    XK_Caps_Lock   // Caps lock
#define EKeySHIFT_LOCK   XK_Shift_Lock  // Shift lock

#define EKeyMETA_L       XK_Meta_L      // Left meta
#define EKeyMETA_R       XK_Meta_R      // Right meta
#define EKeyALT_L        XK_Alt_L       // Left alt
#define EKeyALT_R        XK_Alt_R       // Right alt
#define EKeySuper_L      XK_Super_L     // Left super
#define EKeySuper_R      XK_Super_R     // Right super
#define EKeyHyper_L      XK_Hyper_L     // Left hyper
#define EKeyHyper_R      XK_Hyper_R     // Right hyper



// Keypad Functions, keypad numbers cleverly chosen to map to ascii
//

/*
#define EKeyXK_KP_Space   0xFF80  // space
#define EKeyXK_KP_Tab     0xFF89
#define EKeyXK_KP_Enter   0xFF8D  // enter
#define EKeyXK_KP_F1      0xFF91  // PF1, KP_A, ...
#define EKeyXK_KP_F2      0xFF92
#define EKeyXK_KP_F3      0xFF93
#define EKeyXK_KP_F4      0xFF94
#define EKeyXK_KP_Home    0xFF95
*/
#define EKeyKP_LEFT       XK_KP_Left
#define EKeyKP_UP         XK_KP_Up
#define EKeyKP_RIGHT      XK_KP_Right
#define EKeyKP_DOWN       XK_KP_Down
#define EKeyKP_PRIOR      XK_KP_Prior
#define EKeyKP_PAGE_UP    XK_KP_Page_Up
#define EKeyKP_NEXT       XK_KP_Next
#define EKeyKP_PAGE_DOWN  XK_KP_Page_Down
#define EKeyKP_END        XK_KP_End
#define EKeyKP_BEGIN      XK_KP_Begin
#define EKeyKP_INSERT     XK_KP_Insert
#define EKeyKP_DELETE     XK_KP_Delete
#define EKeyKP_EQUAL      XK_KP_Equal
#define EKeyKP_MULTIPLY   XK_KP_Multiply
#define EKeyKP_ADD        XK_KP_Add
#define EKeyKP_SEPARATOR  XK_KP_Separator
#define EKeyKP_SUBTRACT   XK_KP_Subtract
#define EKeyKP_DECIMAL    XK_KP_Decimal
#define EKeyKP_DIVIDE     XK_KP_Divide

#define EKeyKP_0    XK_KP_0
#define EKeyKP_1    XK_KP_1
#define EKeyKP_2    XK_KP_2
#define EKeyKP_3    XK_KP_3
#define EKeyKP_4    XK_KP_4
#define EKeyKP_5    XK_KP_5
#define EKeyKP_6    XK_KP_6
#define EKeyKP_7    XK_KP_7
#define EKeyKP_8    XK_KP_8
#define EKeyKP_9    XK_KP_9

#endif // EX11


#define EShiftMask    0x0001
#define ELockMask     0x0002
#define EControlMask  0x0004
#define EMod1Mask     0x0008
#define EMod2Mask     0x0010
#define EMod3Mask     0x0020
#define EMod4Mask     0x0040
#define EMod5Mask     0x0080
#define EButton1Mask  0x0100
#define EButton2Mask  0x0200
#define EButton3Mask  0x0400
#define EButton4Mask  0x0800
#define EButton5Mask  0x1000


#ifdef __APPLE__
#define EAltMask         0x2000
#define ECommandMask     EMod2Mask
#define ENumLockMask     0
#else
#define EAltMask      EMod1Mask
#define ENumLockMask  EMod2Mask
#endif	// __APPLE__


#define _EM_KeyEntryInit(pKe) do\
{\
	(pKe)->Name = NULL;\
	(pKe)->Modifiers = 0;\
	(pKe)->Priority = EKeyPRIORITY_LOW;\
	(pKe)->Callback = NULL;\
	(pKe)->ClientData = NULL;\
} while(0)

#define E_KeyTableFree(pTable) do\
{\
	if(pTable)\
	{\
		EIndex  lI = 0;const EIndex  lN = pTable##_Count;EKeyRec*  lKeyRec = pTable;for(;lI < lN;lI++, lKeyRec++)\
		{\
			if(lKeyRec->Entries)\
			{\
				EIndex  lI1 = 0;const EIndex  lN1 = lKeyRec->Entries_Count;EKeyEntry*  lEntry = lKeyRec->Entries;for(;lI1 < lN1;lI1++, lEntry++)\
				{\
					_E_KeyEntryClear(lEntry);\
				}\
				EFree(lKeyRec->Entries);\
			}\
		}\
		EList_Free(pTable);\
	}\
} while(0)


// Used to remap command modifier etc. (Mac)
//
extern EKeyModifiers  E_CommandModifierMask;
extern EKeyModifiers  E_SecondModifierMask;

static inline void _E_KeyEntryClear(EKeyEntry* PEntry)
{
	EFreeChkClr(PEntry->Name);
	_EM_KeyEntryInit(PEntry);
}



#ifdef EX11
extern EIndex _EX_MapXKeyToTableIndex(const XeKeySym PKeySym, const XeModifiers PModifiers);
extern EBool  E_XProcessKey(XeKeySym PKeySym, const XeModifiers PModifiers, const int PKeyEventType);
extern EBool  E_XeProcessKey(XeWidget PW, XeKeySym PKeySym, const XeModifiers PModifiers, const int PKeyEventType);
extern int    XeWidgetKeySetCallback(XeWidget PW, const char* PName, const EKeyCode PKey, const EKeyModifiers PModifiers, const int PKeyEventType,  EKeyCallbackFunc PCallback, EPointer PClientData);
#endif // EX11

extern int    E_KeySetCallback(const char* PName, const EKeyCode PKey, const EKeyModifiers PModifiers, const int PKeyEventType,  EKeyCallbackFunc PCallback, EPointer PClientData);
extern int    E_KeySetInternalCallback(const char* PName, const EKeyCode PKey, const EKeyModifiers PModifiers, const int PKeyEventType,  EKeyCallbackFunc PCallback, EPointer PClientData);

extern int    E_KeyRemoveCallback(const EKeyCode PKey, const EKeyModifiers PModifiers, const int PKeyEventType,  EKeyCallbackFunc PCallback, EPointer PClientData);

extern void   E_PrintKeyTable(void);
extern void   E_InputFree(void);

#ifdef EX11
extern EBool  E_IsKeyDown(XeDisplay* PDisplay, const uint8_t PKey);
#endif

#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}  // Close scope of 'extern "C"' declaration
#endif

#endif // _EInput_h
