/*
 * Copyright 2021-2024, ttcoder of TTS-LLC
 * All rights reserved. Distributed under the terms of the MIT license.
 */


// haiku.lib.so
#include <interface/InterfaceDefs.h>  // B_ESCAPE etc
#include <support/Debug.h>  // STATIC_ASSERT()

// this
#include "_GeInput.h"



// Map
// - from Genode-Nitpicker scan-code
// - to   UTF8 (in fact, ASCII) character, or modifier
//
// Some scancodes/keyboard keys do NOT map to UTF8 of course : modifier keys like SHIFT/CTRL, function keys...
// Those go into <changed_disambiguated_modifier> instead.
//
int hog::conv_input::HaikuKey_for_GeKey(
			const	Input::Keycode genode_scancode,
					int32 & changed_disambiguated_modifier
		)
{
	using namespace Input;
	
	//Genode::log( " converting key with scancode: ", key_name(genode_key) );
	
	// we more or less follow the lead from:
	// - os/src/drivers/framebuffer/sdl/convert_keycode.h
	// - os/include/input/keycodes.h
	// - os/src/drivers/ps2/scan_code_set_1.h
	// - world/src/lib/sdl2/video/SDL_genode_fb_events.cc
	
	switch( genode_scancode ) //xx or "keycode" ?
	{
		case KEY_ESC: return B_ESCAPE;
		
		case KEY_1: return '1';
		case KEY_2: return '2';
		case KEY_3: return '3';
		case KEY_4: return '4';
		case KEY_5: return '5';
		case KEY_6: return '6';
		case KEY_7: return '7';
		case KEY_8: return '8';
		case KEY_9: return '9';
		case KEY_0: return '0';
		case KEY_MINUS:return '-';
		case KEY_EQUAL:return '=';
		case KEY_BACKSPACE: return B_BACKSPACE;
		
		case KEY_TAB: return B_TAB;
		case KEY_Q: return 'q';
		
		case KEY_B: return 'b';
		case KEY_C: return 'c';
		case KEY_D: return 'd';
		case KEY_E: return 'e';
		case KEY_F: return 'f';
		case KEY_G: return 'g';
		case KEY_H: return 'h';
		case KEY_I: return 'i';
		case KEY_J: return 'j';
		case KEY_K: return 'k';
		
		case KEY_N: return 'n';
		case KEY_O: return 'o';
		
		case KEY_R: return 'r';
		case KEY_S: return 's';
		case KEY_T: return 't';
		case KEY_U: return 'u';
		case KEY_V: return 'v';
		case KEY_W: return 'w';
		case KEY_X: return 'x';
		case KEY_Y: return 'y';
		
		case KEY_P: return 'p';
		case KEY_LEFTBRACE:	 return '[';
		case KEY_RIGHTBRACE: return ']';
		case KEY_ENTER: return B_ENTER;  // B_ENTER is an alias for B_RETURN, both equal to 0xa
		
		///later: allow configuration/remapping of CTRL and ALT keys
		case KEY_LEFTCTRL:
			changed_disambiguated_modifier = B_LEFT_CONTROL_KEY;
			return 0;
			//
		
		case KEY_A: return 'a';
		
		case KEY_L: return 'l';
		
		case KEY_SEMICOLON:		return ';';
		case KEY_APOSTROPHE:	return '\'';
///ToDo-2: or maybe this is the " ² " key ? : and KEY_ASTERISK is missing ?  Review the os/include/ headers
		case KEY_GRAVE:			return '\\'; ///?
		
		case KEY_LEFTSHIFT:
			changed_disambiguated_modifier = B_LEFT_SHIFT_KEY;
			return 0;
			//
		case KEY_BACKSLASH: return '\\';
		
		case KEY_Z: return 'z';
		
		case KEY_M: return 'm';
		
		case KEY_COMMA:	return ',';
		case KEY_DOT:	return '.';
		case KEY_SLASH:	return '/';
		case KEY_RIGHTSHIFT:
			changed_disambiguated_modifier = B_RIGHT_SHIFT_KEY;
			return 0;
			//
		
			///later: allow configuration/remapping of CTRL and ALT keys
		case KEY_LEFTALT:
			changed_disambiguated_modifier = B_LEFT_COMMAND_KEY;
			return 0;
			//
		case KEY_SPACE: return B_SPACE;
		
		case KEY_CAPSLOCK:
			changed_disambiguated_modifier = B_CAPS_LOCK;
			return 0;
		
		case KEY_F1:
		case KEY_F2:
		case KEY_F3:
		case KEY_F4:
		case KEY_F5:
		case KEY_F6:
		case KEY_F7:
		case KEY_F8:
		case KEY_F9:
		case KEY_F10:
			// those enums need to be contiguous, for the below 'formula' to be valid
			STATIC_ASSERT( KEY_F10 - KEY_F1 == 10-1 );
			STATIC_ASSERT( B_F10_KEY - B_F1_KEY == 10-1 );
			
			changed_disambiguated_modifier = B_FUNCTION_KEY;
			
			return B_F1_KEY + (genode_scancode - KEY_F1);
		
		case KEY_F11:
		case KEY_F12:
			// F11 and F12 cannot be converted with the above formula as their enums are
			// a distinct set, as confirmed by this failing assert:
			//STATIC_ASSERT( KEY_F12 - KEY_F1 == 12-1 );
			// But this one assertion succeeds, hence the adapted formula:
			
			STATIC_ASSERT( KEY_F12 - KEY_F11 == 12-11 );
			STATIC_ASSERT( B_F12_KEY - B_F11_KEY == 12-11 );
			
			changed_disambiguated_modifier = B_FUNCTION_KEY;
			
			return B_F11_KEY + (genode_scancode - KEY_F11);
		/*
	///ToDo-2: same as above to implement B_NUM_LOCK etc:
		
		KEY_NUMLOCK : changed_modifier = B_NUM_LOCK; return;
		KEY_SCROLLLOCK : changed_modifier = B_SCROLL_LOCK; return;
			B_SCROLL_KEY + B_FUNCTION_KEY ?
				what about these?:
			B_PRINT_KEY + B_FUNCTION_KEY ?
			B_PAUSE_KEY + B_FUNCTION_KEY ?
		*/
		
		// Keypad
		case KEY_KPASTERISK:	return '*';
		case KEY_KP7:	return '7';
		case KEY_KP8:	return '8';
		case KEY_KP9:	return '9';
		case KEY_KPMINUS: return '-';
		case KEY_KP4:	return '4';
		case KEY_KP5:	return '5';
		case KEY_KP6:	return '6';
		case KEY_KPPLUS: return '+';
		case KEY_KP1:	return '1';
		case KEY_KP2:	return '2';
		case KEY_KP3:	return '3';
		case KEY_KP0:	return '0';
		case KEY_KPDOT:	return '.';
		
		case KEY_KPENTER: return B_ENTER;
		
		case KEY_RIGHTCTRL:
			changed_disambiguated_modifier = B_RIGHT_CONTROL_KEY;
			return 0;
			//
		
		case KEY_KPSLASH: return '/';
		/// KEY_SYSRQ ?
		
		case KEY_RIGHTALT:
			changed_disambiguated_modifier = B_RIGHT_COMMAND_KEY;  ///later: allow configuration/remapping of CTRL and ALT keys
			return 0;
			//
		/// KEY_LINEFEED? which key is the "linefeed" key ??
		
		case KEY_HOME: return B_HOME;
		
		case KEY_UP:   return B_UP_ARROW;
		case KEY_PAGEUP: return B_PAGE_UP;
		
		case KEY_LEFT: return B_LEFT_ARROW;
		case KEY_RIGHT:return B_RIGHT_ARROW;
		
		case KEY_END: return B_END;
		case KEY_DOWN: return B_DOWN_ARROW;
		
		case KEY_PAGEDOWN: return B_PAGE_DOWN;
		case KEY_INSERT: return B_INSERT;
		case KEY_DELETE: return B_DELETE;
		
		//KEY_MACRO ?
		case KEY_MUTE:
		case KEY_VOLUMEDOWN:
		case KEY_VOLUMEUP:
			Genode::warning( "Volume-Related key ? Un-implemented event...: ", (int)genode_scancode );
		break;
		//KEY_POWER ?
		//KEY_KPEQUAL ?
		//KEY_LEFTMETA ?
		//KEY_RIGHTMETA ?
		
		default:
///ToDo-2: key repeat does not work, and getting "un-inplemented event 510" when keeping a key depressed (i.e. repeating)...
			Genode::warning( "Un-implemented keyboard event: ", (int)genode_scancode );
	}
	
	return 0;
}



int hog::conv_input::ModifiedKey_for_RawBeKey(
			int raw_be_key,
			int virtualized_modifiers
		)
{
	if( virtualized_modifiers & B_SHIFT_KEY )
	{
		// Letters -> toupper:
		if( raw_be_key >= 'a' && raw_be_key <= 'z' )
			//
			return raw_be_key + 'A' - 'a';
			//
		
		switch( raw_be_key )
		{
			// Digits/top row:
			case '1': return '!';
			case '2': return '@';
			case '3': return '#';
			case '4': return '$';
			case '5': return '%';
			case '6': return '^';
			case '7': return '&';
			case '8': return '*';
			case '9': return '(';
			case '0': return ')';
			case '-': return '_';
			case '=': return '+';
			// braces:
			case '[': return '{';
			case ']': return '}';
			// semicolon/apostrophe/grave:
			case ';': return ':';
			case '\'': return '\"';
			case '\\': return '|';
			// comma/dot/slash:
			case ',': return '<';
			case '.': return '>';
	///ToDo-2:  this key mapping cannot work accurately as there are several (keypad etc) keys that yield '/' !... Ought to map directly from the genode scancode instead of the be_key...
			case '/': return '?';
		}
		
		// all(?) the other keys are un-modified in the SHIFT table, return as-is:
		return raw_be_key;
	}
	
	// modifiers == 0 -> return the unmodified key
	return raw_be_key;
}


