// license:BSD-3-Clause
// copyright-holders:Peter Trauner, Kevin Thacker
/**********************************************************************

    pckeybrd.c

    PC-style keyboard emulation

    This emulation is decoupled from the AT 8042 emulation used in the
    IBM ATs and above

**********************************************************************/

/* Todo: (added by KT 22-Jun-2000
    1. Check scancodes I have added are the actual scancodes for set 2 or 3.
    2. Check how codes are changed based on Shift/Control states for those sets
       that require it - info in Help PC!

*/

#include "emu.h"
#include "pckeybrd.h"
#include "natkeyboard.h"

/* AT keyboard documentation comes from www.beyondlogic.org and HelpPC documentation */

/* to enable logging of keyboard read/writes */
#define LOG_KEYBOARD    0


/*
    The PS/2 models have three make/break scan code sets.  The first
      set matches the PC & XT make/break scan code set and is the one
      listed here.  Scan code sets are selected by writing the value F0
      to the keyboard via the ~8042~ (port 60h).  The following is a brief
      description of the scan code sets (see the PS/2 Technical Reference
      manuals for more information on scan code sets 2 and 3):

    *  set 1, each key has a base scan code.  Some keys generate
       extra scan codes to generate artificial shift states.  This
       is similar to the standard scan code set used on the PC and XT.
    *  set 2, each key sends one make scan code and two break scan
       codes bytes (F0 followed by the make code).  This scan code
       set is available on the IBM AT also.
    *  set 3, each key sends one make scan code and two break scan
       codes bytes (F0 followed by the make code) and no keys are
       altered by Shift/Alt/Ctrl keys.
    *  typematic scan codes are the same as the make scan code

*/


/* using the already existing input port definitions, this table re-maps
to scancode set 3.
I don't have the details for scan-code set 2,3 but they sound very similar
to the scancode set I have here. - KT 22/Jun/2000 */


/* key set 3 */
const int at_keyboard_device::m_scancode_set_2_3[]=
{
	0,
	0x076,
	0x016,
	0x01e,
	0x026,
	0x025,
	0x02e,
	0x036,
	0x03d,
	0x03e,
	0x046,
	0x045,
	0x04e,
	0x055,
	0x066,
	0x00d,
	0x015,
	0x01d,
	0x024,
	0x02d,
	0x02c,
	0x035,
	0x03c,
	0x043,
	0x044,
	0x04d,
	0x054,
	0x05b,
	0x05a,
	0x014,
	0x01c,
	0x01b,
	0x023,
	0x02b,
	0x034,
	0x033,
	0x03b,
	0x042,
	0x04b,
	0x04c,
	0x052,
	0x00e,
	0x012,
	0x05d,
	0x01a,
	0x022,
	0x021,
	0x02a,
	0x032,
	0x031,
	0x03a,
	0x041,
	0x049,
	0x04a,
	0x059,
	0x000,
	0x011,
	0x029,
	0x058,
	0x05,
	0x06,
	0x04,
	0x0c,
	0x03,
	0x0b,
	0x083,
	0x0a,
	0x01,
	0x09,
	0x077,
	0x07e,
	0x06c,
	0x075,
	0x07d,
	0x07b,
	0x06b,
	0x073,
	0x074,
	0x079,
	0x069,
	0x072,
	0x07a,
	0x070,
	0x071,
	0x00,
	0x00,
	0x078,
	0x07,
	0x05a,
	0x014,
	0x04a,
	0x000,
	0x011,
	0x06c,
	0x075,
	0x07d,
	0x06b,
	0x074,
	0x069,
	0x072,
	0x07a,
	0x070,
	0x071,
	0x000,
	0x000,
	0x000
};


const at_keyboard_device::extended_keyboard_code at_keyboard_device::m_mf2_code[0x10][2/*numlock off, on*/]={
	{   { "\xe0\x1c", "\xe0\x9c" } }, // keypad enter
	{   { "\xe0\x1d", "\xe0\x9d" } }, // right control
	{   { "\xe0\x35", "\xe0\xb5" } },
	{   { "\xe0\x37", "\xe0\xb7" } },
	{   { "\xe0\x38", "\xe0\xb8" } },
	{   { "\xe0\x47", "\xe0\xc7" }, { "\xe0\x2a\xe0\x47", "\xe0\xc7\xe0\xaa" } },
	{   { "\xe0\x48", "\xe0\xc8" }, { "\xe0\x2a\xe0\x48", "\xe0\xc8\xe0\xaa" } },
	{   { "\xe0\x49", "\xe0\xc9" }, { "\xe0\x2a\xe0\x49", "\xe0\xc9\xe0\xaa" } },
	{   { "\xe0\x4b", "\xe0\xcb" }, { "\xe0\x2a\xe0\x4b", "\xe0\xcb\xe0\xaa" } },
	{   { "\xe0\x4d", "\xe0\xcd" }, { "\xe0\x2a\xe0\x4d", "\xe0\xcd\xe0\xaa" } },
	{   { "\xe0\x4f", "\xe0\xcf" }, { "\xe0\x2a\xe0\x4f", "\xe0\xcf\xe0\xaa" } },
	{   { "\xe0\x50", "\xe0\xd0" }, { "\xe0\x2a\xe0\x50", "\xe0\xd0\xe0\xaa" } },
	{   { "\xe0\x51", "\xe0\xd1" }, { "\xe0\x2a\xe0\x51", "\xe0\xd1\xe0\xaa" } },
	{   { "\xe0\x52", "\xe0\xd2" }, { "\xe0\x2a\xe0\x52", "\xe0\xd2\xe0\xaa" } },
	{   { "\xe0\x53", "\xe0\xd3" }, { "\xe0\x2a\xe0\x53", "\xe0\xd3\xe0\xaa" } },
	{   { "\xe1\x1d\x45\xe1\x9d\xc5" }, { "\xe0\x2a\xe1\x1d\x45\xe1\x9d\xc5" } }
};

/* I don't think these keys change if num-lock is active! */
/* pc-at extended keyboard make/break codes for code set 3 */
const at_keyboard_device::extended_keyboard_code at_keyboard_device::m_extended_codes_set_2_3[]=
{
	/*keypad enter */
	{
		"\xe0\x5a",
		"\xe0\xf0\x5a"
	},
	/* right control */
	{
		"\xe0\x14",
		"\xe0\xf0\x14"
	},
	/* keypad slash */
	{
		"\xe0\x4a",
		"\xe0\xf0\x4a"
	},
	/* print screen */
	{
		"\xe0\x12\xe0\x7c",
		nullptr, /* I don't know the break sequence */

	},
	/* right alt */
	{
		"\xe0\x11",
		"\xe0\xf0\x11"
	},
	/* home */
	{
		"\xe0\x6c",
		"\xe0\xf0\x6c"
	},
	/* cursor up */
	{
		"\xe0\x75",
		"\xe0\xf0\x75"
	},
	/* page up */
	{
		"\xe0\x7d",
		"\xe0\xf0\x7d"
	},
	/* cursor left */
	{
		"\xe0\x6b",
		"\xe0\xf0\x6b",
	},
	/* cursor right */
	{
		"\xe0\x74",
		"\xe0\xf0\x74"
	},
	/* end */
	{
		"\xe0\x69",
		"\xe0\xf0\x69",
	},
	/* cursor down */
	{
		"\xe0\x72",
		"\xe0\xf0\x72"
	},
	/* page down */
	{
		"\xe0\x7a",
		"\xe0\xf0\x7a"
	},
	/* insert */
	{
		"\xe0\x70",
		"\xe0\xf0\x70",
	},
	/* delete */
	{
		"\xe0\x71",
		"\xe0\xf0\x71"
	},
	/* pause */
	{
		"\xe1\x14\x77\xe1\xf0\x14\xf0\x77",
		nullptr, /*?? I don't know the break sequence */
	}

};

DEFINE_DEVICE_TYPE(PC_KEYB, pc_keyboard_device, "pc_keyb", "PC Keyboard")
DEFINE_DEVICE_TYPE(AT_KEYB, at_keyboard_device, "at_keyb", "AT Keyboard")

pc_keyboard_device::pc_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	pc_keyboard_device(mconfig, PC_KEYB, tag, owner, clock)
{
	m_type = KEYBOARD_TYPE::PC;
}

pc_keyboard_device::pc_keyboard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, type, tag, owner, clock),
	m_ioport(*this, ":pc_keyboard_%u", 0),
	m_out_keypress_func(*this)
{
}

at_keyboard_device::at_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	pc_keyboard_device(mconfig, AT_KEYB, tag, owner, clock),
	m_scan_code_set(1)
{
	m_type = KEYBOARD_TYPE::AT;
}


void pc_keyboard_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	polling();
	if(!charqueue_empty())
		m_out_keypress_func(1);
}

void pc_keyboard_device::device_start()
{
	save_item(NAME(m_delay));
	save_item(NAME(m_repeat));
	save_item(NAME(m_numlock));
	save_item(NAME(m_on));
	save_item(NAME(m_head));
	save_item(NAME(m_tail));
	save_pointer(NAME(m_queue), ARRAY_LENGTH(m_queue));
	save_pointer(NAME(m_make), ARRAY_LENGTH(m_make));

	memset(m_make, 0, sizeof(m_make));

	machine().ioport().natkeyboard().configure(
		ioport_queue_chars_delegate(&pc_keyboard_device::queue_chars, this),
		ioport_accept_char_delegate(&pc_keyboard_device::accept_char, this),
		ioport_charqueue_empty_delegate(&pc_keyboard_device::charqueue_empty, this));

	m_out_keypress_func.resolve_safe();
	m_keyboard_timer = timer_alloc();
}

void at_keyboard_device::device_start()
{
	save_item(NAME(m_scan_code_set));
	save_item(NAME(m_input_state));
	pc_keyboard_device::device_start();
}

void pc_keyboard_device::device_reset()
{
	m_delay = 60;
	m_repeat = 8;
	m_numlock = 0;
	m_on = true;
	/* set default led state */
	machine().output().set_led_value(2, 0);
	machine().output().set_led_value(0, 0);
	machine().output().set_led_value(1, 0);

	m_head = m_tail = 0;
	queue_insert(0xaa);
	m_keyboard_timer->adjust(attotime::from_msec(5), 0, attotime::from_hz(60));
}

void at_keyboard_device::device_reset()
{
	m_input_state = 0;
	pc_keyboard_device::device_reset();
}

WRITE_LINE_MEMBER(pc_keyboard_device::enable)
{
	if(state && !m_on)
	{
		if(m_type == KEYBOARD_TYPE::PC)
			reset();
		else
			m_keyboard_timer->adjust(attotime::from_msec(5), 0, attotime::from_hz(60));
	}
	else if(!state)
		m_keyboard_timer->adjust(attotime::never);

	m_on = state ? true : false;
}

/* insert a code into the buffer */
void pc_keyboard_device::queue_insert(uint8_t data)
{
	if (LOG_KEYBOARD)
		logerror("keyboard queueing %.2x\n",data);

	m_queue[m_head] = data;
	m_head++;
	m_head %= ARRAY_LENGTH(m_queue);
}


int pc_keyboard_device::queue_size(void)
{
	int queue_size;
	queue_size = m_head - m_tail;
	if (queue_size < 0)
		queue_size += ARRAY_LENGTH(m_queue);
	return queue_size;
}

void pc_keyboard_device::standard_scancode_insert(int our_code, int pressed)
{
	if (!pressed)
	{
		/* adjust code for break code */
		our_code|=0x080;
	}
	queue_insert(our_code);
}

/* add codes for standard keys */
void at_keyboard_device::standard_scancode_insert(int our_code, int pressed)
{
	int scancode;

	switch (m_scan_code_set)
	{
		case 1:
		default:
		{
			/* the original code was designed for this set, and there is
			a 1:1 correspondance for the scancodes */
			scancode = our_code;

			if (!pressed)
			{
				/* adjust code for break code */
				scancode|=0x080;
			}
		}
		break;

		case 2:
		case 3:
		{
			/* lookup scancode */
			scancode = m_scancode_set_2_3[our_code];

			if (!pressed)
			{
				/* break code */
				queue_insert(0x0f0);
			}

		}
		break;
	}

	queue_insert(scancode);
}

void at_keyboard_device::extended_scancode_insert(int code, int pressed)
{
	code = code - 0x060;

	switch (m_scan_code_set)
	{
		case 1:
		default:
		{
			if (pressed)
			{
				if (m_mf2_code[code][m_numlock].pressed)
					helper(m_mf2_code[code][m_numlock].pressed);
				else
					helper(m_mf2_code[code][0].pressed);
			}
			else
			{
				if (m_mf2_code[code][m_numlock].released)
					helper(m_mf2_code[code][m_numlock].released);
				else if (m_mf2_code[code][0].released)
					helper(m_mf2_code[code][0].released);
			}
		}
		break;

		case 2:
		case 3:
		{
			const extended_keyboard_code *key = &m_extended_codes_set_2_3[code];

			if (pressed)
			{
				if (key->pressed)
				{
					helper(key->pressed);
				}
			}
			else
			{
				if (key->released)
				{
					helper(key->released);
				}
			}
		}
		break;
	}

}

/* add a list of codes to the keyboard buffer */
void at_keyboard_device::helper(const char *codes)
{
	int i;
	for (i = 0; codes[i]; i++)
		queue_insert(codes[i]);
}

/**************************************************************************
 *  scan keys and stuff make/break codes
 **************************************************************************/

uint32_t pc_keyboard_device::readport(int port)
{
	if ((m_ioport.size() > port) && m_ioport[port].found())
		return m_ioport[port]->read();
	else
		return 0;
}

void pc_keyboard_device::polling(void)
{
	int i;

	if (m_on)
	{
		/* add codes for keys that are set */
		for( i = 0x01; i < 0x80; i++  )
		{
			if (i==0x60) i+=0x10; // keys 0x60..0x6f need special handling

			if( readport(i/16) & (1 << (i & 15)) )
			{
				if( m_make[i] == 0 )
				{
					m_make[i] = 1;

					if (i==0x45) m_numlock^=1;

					standard_scancode_insert(i,1);
				}
				else if((i != 0x45) && (i != 0x3a)) // don't send repeats for caps or num lock
				{
					m_make[i] += 1;

					if( m_make[i] == m_delay )
					{
						standard_scancode_insert(i, 1);
					}
					else
					{
						if( m_make[i] == m_delay + m_repeat )
						{
							m_make[i] = m_delay;
							standard_scancode_insert(i, 1);
						}
					}
				}
			}
			else
			{
				if( m_make[i] )
				{
					m_make[i] = 0;

					standard_scancode_insert(i, 0);
				}
			}
		}

		if(m_type != KEYBOARD_TYPE::PC)
		{
			/* extended scan-codes */
			for( i = 0x60; i < 0x70; i++  )
			{
				if( readport(i/16) & (1 << (i & 15)) )
				{
					if( m_make[i] == 0 )
					{
						m_make[i] = 1;

						extended_scancode_insert(i,1);

					}
					else
					{
						m_make[i] += 1;
						if( m_make[i] == m_delay )
						{
							extended_scancode_insert(i, 1);
						}
						else
						{
							if( m_make[i] == m_delay + m_repeat )
							{
								m_make[i]=m_delay;

								extended_scancode_insert(i, 1);
							}
						}
					}
				}
				else
				{
					if( m_make[i] )
					{
						m_make[i] = 0;

						extended_scancode_insert(i,0);
					}
				}
			}
		}
	}
}

READ8_MEMBER(pc_keyboard_device::read)
{
	int data;
	if (m_tail == m_head)
		return 0;

	data = m_queue[m_tail];

	if (LOG_KEYBOARD)
		logerror("read(): Keyboard Read 0x%02x\n",data);

	m_tail++;
	m_tail %= ARRAY_LENGTH(m_queue);
	return data;
}

void pc_keyboard_device::clear_buffer(void)
{
	m_head = m_tail = 0;
}

void at_keyboard_device::clear_buffer_and_acknowledge(void)
{
	clear_buffer();
	queue_insert(0x0fa);
}

/* From Ralf Browns Interrupt list:

Values for keyboard commands (data also goes to PORT 0060h):
Value   Count   Description
 EDh    double  set/reset mode indicators Caps Num Scrl
        bit 2 = CapsLk, bit 1 = NumLk, bit 0 = ScrlLk
        all other bits must be zero.
 EEh    sngl    diagnostic echo. returns EEh.
 EFh    sngl    NOP (No OPeration). reserved for future use
 EF+26h double  [Cherry MF2 G80-1501HAD] read 256 bytes of chipcard data
        keyboard must be disabled before this and has to
        be enabled after finished.
 F0h    double  get/set scan code set
        00h get current set
        01h scancode set 1 (PCs and PS/2 mod 30, except Type 2 ctrlr)

        02h scancode set 2 (ATs, PS/2, default)
        03h scancode set 3
 F2h    sngl    read keyboard ID (read two ID bytes)
        AT keyboards returns FA (ACK)
        MF2 returns AB 41 (translation) or
                AB 83 (pass through)
 F3h    double  set typematic rate/delay
        format of the second byte:
        bit7=0 : reserved
        bit6-5 : typemativ delay
             00b=250ms     10b= 750ms
             01b=500ms     11b=1000ms
        bit4-0 : typematic rate (see #P050)
 F4h    sngl    enable keyboard
 F5h    sngl    disable keyboard. set default parameters (no keyboard scanning)
 F6h    sngl    set default parameters
 F7h    sngl    [MCA] set all keys to typematic (scancode set 3)

 F8h    sngl    [MCA] set all keys to make/release
 F9h    sngl    [MCA] set all keys to make only
 FAh    sngl    [MCA] set all keys to typematic/make/release
 FBh    sngl    [MCA] set al keys to typematic
 FCh    double  [MCA] set specific key to make/release
 FDh    double  [MCA] set specific key to make only
 FEh    sngl    resend last scancode
 FFh    sngl    perform internal power-on reset function
Note:   each command is acknowledged by FAh (ACK), if not mentioned otherwise.
      See PORT 0060h-R for details.
SeeAlso: #P046
*/

WRITE8_MEMBER(at_keyboard_device::write)
{
	if (LOG_KEYBOARD)
		logerror("keyboard write %.2x\n",data);

	switch (m_input_state)
	{
		case 0:
			switch (data) {
			case 0xed: // leds schalten
				/* acknowledge */
				queue_insert(0x0fa);
				/* now waiting for  code... */
				m_input_state=1;
				break;
			case 0xee: // echo
				/* echo code with no acknowledge */
				queue_insert(0xee);
				break;
			case 0xf0: // scancodes adjust
				/* acknowledge */
				clear_buffer_and_acknowledge();
				/* waiting for data */
				m_input_state=2;
				break;
			case 0xf2: // identify keyboard
				/* ack and two byte keyboard id */
				queue_insert(0xfa);

				/* send keyboard code */
				if (m_type == KEYBOARD_TYPE::MF2) {
					queue_insert(0xab);
					queue_insert(0x41);
				}
				else
				{
					/* from help-pc docs */
					queue_insert(0x0ab);
					queue_insert(0x083);
				}

				break;
			case 0xf3: // adjust rates
				/* acknowledge */
				queue_insert(0x0fa);

				m_input_state=3;
				break;
			case 0xf4: // activate
				clear_buffer_and_acknowledge();

				enable(1);
				break;
			case 0xf5:
				/* acknowledge */
				clear_buffer_and_acknowledge();
				// standardvalues
				enable(0);
				break;
			case 0xf6:
				clear_buffer_and_acknowledge();
				// standardvalues
				enable(1);
				break;
			case 0xfe: // resend
				// should not happen, for now send 0
				queue_insert(0);    //m_last_code);
				break;
			case 0xff: // reset
				/* it doesn't state this in the docs I have read, but I assume
				that the keyboard input buffer is cleared. The PCW16 sends &ff,
				and requires that 0x0fa is the first byte to be read */

				reset();
				clear_buffer_and_acknowledge();
				queue_insert(0xaa);
			break;
			}
			break;
		case 1:
			/* code received */
			m_input_state=0;

			/* command? */
			if (data & 0x080)
			{
				/* command received instead of code - execute command */
				write(space, offset, data);
			}
			else
			{
				/* send acknowledge */
				queue_insert(0x0fa);

				/* led  bits */
				/* bits: 0 scroll lock, 1 num lock, 2 capslock */

				/* led's in same order as my keyboard leds. */
				/* num lock, caps lock, scroll lock */
				machine().output().set_led_value(2, (data & 0x01));
				machine().output().set_led_value(0, ((data & 0x02)>>1));
				machine().output().set_led_value(1, ((data & 0x04)>>2));

			}
			break;
		case 2:
			m_input_state=0;

			/* command? */
			if (data & 0x080)
			{
				/* command received instead of code - execute command */
				write(space, offset, data);
			}
			else
			{
				/* 00  return byte indicating scan code set in use
				01  select scan code set 1  (used on PC & XT)
				02  select scan code set 2
				03  select scan code set 3
				*/

				if (data == 0x00)
				{
						queue_insert(m_scan_code_set);
				}
				else
				{
					if(data && (data <= 3))
						m_scan_code_set = data;
				}
			}

			break;
		case 3:
			/* 6,5: 250ms, 500ms, 750ms, 1s */
			/* 4..0: 30 26.7 .... 2 chars/s*/

			/* command? */
			m_input_state=0;
			if (data & 0x080)
			{
				/* command received instead of code - execute command */
				write(space, offset, data);
			}
			else
			{
				/* received keyboard repeat */

			}

			break;
	}
}

/***************************************************************************
  unicode_char_to_at_keycode
***************************************************************************/

uint8_t pc_keyboard_device::unicode_char_to_at_keycode(char32_t ch)
{
	uint8_t b;
	switch(ch)
	{
		case '\033':                    b = 1;      break;
		case '1':                       b = 2;      break;
		case '2':                       b = 3;      break;
		case '3':                       b = 4;      break;
		case '4':                       b = 5;      break;
		case '5':                       b = 6;      break;
		case '6':                       b = 7;      break;
		case '7':                       b = 8;      break;
		case '8':                       b = 9;      break;
		case '9':                       b = 10;     break;
		case '0':                       b = 11;     break;
		case '-':                       b = 12;     break;
		case '=':                       b = 13;     break;
		case '\010':                    b = 14;     break;
		case '\t':                      b = 15;     break;
		case 'q':                       b = 16;     break;
		case 'w':                       b = 17;     break;
		case 'e':                       b = 18;     break;
		case 'r':                       b = 19;     break;
		case 't':                       b = 20;     break;
		case 'y':                       b = 21;     break;
		case 'u':                       b = 22;     break;
		case 'i':                       b = 23;     break;
		case 'o':                       b = 24;     break;
		case 'p':                       b = 25;     break;
		case '[':                       b = 26;     break;
		case ']':                       b = 27;     break;
		case '\r':                      b = 28;     break;
		case UCHAR_MAMEKEY(CAPSLOCK):   b = 29;     break;
		case 'a':                       b = 30;     break;
		case 's':                       b = 31;     break;
		case 'd':                       b = 32;     break;
		case 'f':                       b = 33;     break;
		case 'g':                       b = 34;     break;
		case 'h':                       b = 35;     break;
		case 'j':                       b = 36;     break;
		case 'k':                       b = 37;     break;
		case 'l':                       b = 38;     break;
		case ';':                       b = 39;     break;
		case '\'':                      b = 40;     break;
		case '`':                       b = 41;     break;
		case '\\':                      b = 43;     break;
		case 'z':                       b = 44;     break;
		case 'x':                       b = 45;     break;
		case 'c':                       b = 46;     break;
		case 'v':                       b = 47;     break;
		case 'b':                       b = 48;     break;
		case 'n':                       b = 49;     break;
		case 'm':                       b = 50;     break;
		case ',':                       b = 51;     break;
		case '.':                       b = 52;     break;
		case '/':                       b = 53;     break;
		case ' ':                       b = 0x39;   break;
		case UCHAR_MAMEKEY(F1):         b = 0x3b;   break;
		case UCHAR_MAMEKEY(F2):         b = 0x3c;   break;
		case UCHAR_MAMEKEY(F3):         b = 0x3d;   break;
		case UCHAR_MAMEKEY(F4):         b = 0x3e;   break;
		case UCHAR_MAMEKEY(F5):         b = 0x3f;   break;
		case UCHAR_MAMEKEY(F6):         b = 0x40;   break;
		case UCHAR_MAMEKEY(F7):         b = 0x41;   break;
		case UCHAR_MAMEKEY(F8):         b = 0x42;   break;
		case UCHAR_MAMEKEY(F9):         b = 0x43;   break;
		case UCHAR_MAMEKEY(F10):        b = 0x44;   break;
		case UCHAR_MAMEKEY(NUMLOCK):    b = 0x45;   break;
		case UCHAR_MAMEKEY(SCRLOCK):    b = 0x46;   break;
		case UCHAR_MAMEKEY(7_PAD):      b = 0x47;   break;
		case UCHAR_MAMEKEY(8_PAD):      b = 0x48;   break;
		case UCHAR_MAMEKEY(9_PAD):      b = 0x49;   break;
		case UCHAR_MAMEKEY(MINUS_PAD):  b = 0x4a;   break;
		case UCHAR_MAMEKEY(4_PAD):      b = 0x4b;   break;
		case UCHAR_MAMEKEY(5_PAD):      b = 0x4c;   break;
		case UCHAR_MAMEKEY(6_PAD):      b = 0x4d;   break;
		case UCHAR_MAMEKEY(PLUS_PAD):   b = 0x4e;   break;
		case UCHAR_MAMEKEY(1_PAD):      b = 0x4f;   break;
		case UCHAR_MAMEKEY(2_PAD):      b = 0x50;   break;
		case UCHAR_MAMEKEY(3_PAD):      b = 0x51;   break;
		case UCHAR_MAMEKEY(0_PAD):      b = 0x52;   break;
		case UCHAR_MAMEKEY(DEL_PAD):    b = 0x53;   break;
		case UCHAR_MAMEKEY(F11):        b = 0x57;   break;
		case UCHAR_MAMEKEY(F12):        b = 0x58;   break;
		case '~':                       b = 0x81;   break;
		case '!':                       b = 0x82;   break;
		case '@':                       b = 0x83;   break;
		case '#':                       b = 0x84;   break;
		case '$':                       b = 0x85;   break;
		case '%':                       b = 0x86;   break;
		case '^':                       b = 0x87;   break;
		case '&':                       b = 0x88;   break;
		case '*':                       b = 0x89;   break;
		case '(':                       b = 0x8a;   break;
		case ')':                       b = 0x8b;   break;
		case '_':                       b = 0x8c;   break;
		case '+':                       b = 0x8d;   break;
		case 'Q':                       b = 0x90;   break;
		case 'W':                       b = 0x91;   break;
		case 'E':                       b = 0x92;   break;
		case 'R':                       b = 0x93;   break;
		case 'T':                       b = 0x94;   break;
		case 'Y':                       b = 0x95;   break;
		case 'U':                       b = 0x96;   break;
		case 'I':                       b = 0x97;   break;
		case 'O':                       b = 0x98;   break;
		case 'P':                       b = 0x99;   break;
		case '{':                       b = 0x9a;   break;
		case '}':                       b = 0x9b;   break;
		case 'A':                       b = 0x9e;   break;
		case 'S':                       b = 0x9f;   break;
		case 'D':                       b = 0xa0;   break;
		case 'F':                       b = 0xa1;   break;
		case 'G':                       b = 0xa2;   break;
		case 'H':                       b = 0xa3;   break;
		case 'J':                       b = 0xa4;   break;
		case 'K':                       b = 0xa5;   break;
		case 'L':                       b = 0xa6;   break;
		case ':':                       b = 0xa7;   break;
		case '\"':                      b = 0xa8;   break;
		case '|':                       b = 0xab;   break;
		case 'Z':                       b = 0xac;   break;
		case 'X':                       b = 0xad;   break;
		case 'C':                       b = 0xae;   break;
		case 'V':                       b = 0xaf;   break;
		case 'B':                       b = 0xb0;   break;
		case 'N':                       b = 0xb1;   break;
		case 'M':                       b = 0xb2;   break;
		case '<':                       b = 0xb3;   break;
		case '>':                       b = 0xb4;   break;
		case '?':                       b = 0xb5;   break;
		default:                        b = 0;      break;
	}
	return b;
}

/***************************************************************************
  queue_chars
***************************************************************************/

int pc_keyboard_device::queue_chars(const char32_t *text, size_t text_len)
{
	int i;
	uint8_t b;

	for (i = 0; (i < text_len) && ((queue_size()) + 4 < sizeof(m_queue)); i++)
	{
		b = unicode_char_to_at_keycode(text[i]);
		if (b)
		{
			if (b & 0x80)
				standard_scancode_insert(0x36, 1);

			standard_scancode_insert(b & 0x7f, 1);
			standard_scancode_insert(b & 0x7f, 0);

			if (b & 0x80)
				standard_scancode_insert(0x36, 0);
		}
	}
	return i;
}



/***************************************************************************
  Keyboard declaration
***************************************************************************/

INPUT_PORTS_START( pc_keyboard )
	PORT_START("pc_keyboard_0")
	PORT_BIT ( 0x0001, 0x0000, IPT_UNUSED )     /* unused scancode 0 */
	PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)            /* Esc                         01  81 */
	PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')  /* 1                           02  82 */
	PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')  /* 2                           03  83 */
	PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')  /* 3                           04  84 */
	PORT_BIT( 0x0020, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')  /* 4                           05  85 */
	PORT_BIT( 0x0040, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')  /* 5                           06  86 */
	PORT_BIT( 0x0080, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')  /* 6                           07  87 */
	PORT_BIT( 0x0100, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')  /* 7                           08  88 */
	PORT_BIT( 0x0200, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')  /* 8                           09  89 */
	PORT_BIT( 0x0400, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')  /* 9                           0A  8A */
	PORT_BIT( 0x0800, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')  /* 0                           0B  8B */
	PORT_BIT( 0x1000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')  /* -                           0C  8C */
	PORT_BIT( 0x2000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') /* =                           0D  8D */
	PORT_BIT( 0x4000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)           /* Backspace                   0E  8E */
	PORT_BIT( 0x8000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)         /* Tab                         0F  8F */

	PORT_START("pc_keyboard_1")
	PORT_BIT( 0x0001, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') /* Q                           10  90 */
	PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W') /* W                           11  91 */
	PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E') /* E                           12  92 */
	PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R') /* R                           13  93 */
	PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T') /* T                           14  94 */
	PORT_BIT( 0x0020, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') /* Y                           15  95 */
	PORT_BIT( 0x0040, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U') /* U                           16  96 */
	PORT_BIT( 0x0080, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I') /* I                           17  97 */
	PORT_BIT( 0x0100, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O') /* O                           18  98 */
	PORT_BIT( 0x0200, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P') /* P                           19  99 */
	PORT_BIT( 0x0400, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') /* [                           1A  9A */
	PORT_BIT( 0x0800, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') /* ]                           1B  9B */
	PORT_BIT( 0x1000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) /* Enter                       1C  9C */
	PORT_BIT( 0x2000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))      /* Left Ctrl                   1D  9D */
	PORT_BIT( 0x4000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') /* A                           1E  9E */
	PORT_BIT( 0x8000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') /* S                           1F  9F */

	PORT_START("pc_keyboard_2")
	PORT_BIT( 0x0001, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D') /* D                           20  A0 */
	PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F') /* F                           21  A1 */
	PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G') /* G                           22  A2 */
	PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H') /* H                           23  A3 */
	PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J') /* J                           24  A4 */
	PORT_BIT( 0x0020, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K') /* K                           25  A5 */
	PORT_BIT( 0x0040, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L') /* L                           26  A6 */
	PORT_BIT( 0x0080, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') /* ;                           27  A7 */
	PORT_BIT( 0x0100, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('\"') /* '                           28  A8 */
	PORT_BIT( 0x0200, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') /* `                           29  A9 */
	PORT_BIT( 0x0400, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT)) /* Left Shift                  2A  AA */
	PORT_BIT( 0x0800, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') /* \                           2B  AB */
	PORT_BIT( 0x1000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') /* Z                           2C  AC */
	PORT_BIT( 0x2000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') /* X                           2D  AD */
	PORT_BIT( 0x4000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C') /* C                           2E  AE */
	PORT_BIT( 0x8000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V') /* V                           2F  AF */

	PORT_START("pc_keyboard_3")
	PORT_BIT( 0x0001, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B') /* B                           30  B0 */
	PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N') /* N                           31  B1 */
	PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M') /* M                           32  B2 */
	PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') /* ,                           33  B3 */
	PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') /* .                           34  B4 */
	PORT_BIT( 0x0020, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') /* /                           35  B5 */
	PORT_BIT( 0x0040, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT)) /* Right Shift                 36  B6 */
	PORT_BIT( 0x0080, 0x0000, IPT_KEYBOARD) PORT_NAME("KP * (PrtScr)") PORT_CODE(KEYCODE_ASTERISK)      /* Keypad *  (PrtSc)           37  B7 */
	PORT_BIT( 0x0100, 0x0000, IPT_KEYBOARD) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT)                    /* Left Alt                    38  B8 */
	PORT_BIT( 0x0200, 0x0000, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')  /* Space                       39  B9 */
	PORT_BIT( 0x0400, 0x0000, IPT_KEYBOARD) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK)               /* Caps Lock                   3A  BA */
	PORT_BIT( 0x0800, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))          /* F1                          3B  BB */
	PORT_BIT( 0x1000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))          /* F2                          3C  BC */
	PORT_BIT( 0x2000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))          /* F3                          3D  BD */
	PORT_BIT( 0x4000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))          /* F4                          3E  BE */
	PORT_BIT( 0x8000, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))          /* F5                          3F  BF */

	PORT_START("pc_keyboard_4")
	PORT_BIT( 0x0001, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))           /* F6                          40  C0 */
	PORT_BIT( 0x0002, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))           /* F7                          41  C1 */
	PORT_BIT( 0x0004, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))           /* F8                          42  C2 */
	PORT_BIT( 0x0008, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))           /* F9                          43  C3 */
	PORT_BIT( 0x0010, 0x0000, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))         /* F10                         44  C4 */
	PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NumLock") PORT_CODE(KEYCODE_NUMLOCK)     /* Num Lock                    45  C5 */
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ScrLock") PORT_CODE(KEYCODE_SCRLOCK)     /* Scroll Lock                 46  C6 */
	PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 7 (Home)") PORT_CODE(KEYCODE_7_PAD) PORT_CODE(KEYCODE_HOME )  /* Keypad 7  (Home)            47  C7 */
	PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 8 (Up)") PORT_CODE(KEYCODE_8_PAD) PORT_CODE(KEYCODE_UP )    /* Keypad 8  (Up arrow)        48  C8 */
	PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 9 (PgUp)") PORT_CODE(KEYCODE_9_PAD) PORT_CODE(KEYCODE_PGUP)   /* Keypad 9  (PgUp)            49  C9 */
	PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP -") PORT_CODE(KEYCODE_MINUS_PAD)     /* Keypad -                    4A  CA */
	PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 4 (Left)") PORT_CODE(KEYCODE_4_PAD) PORT_CODE(KEYCODE_LEFT )  /* Keypad 4  (Left arrow)      4B  CB */
	PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD)     /* Keypad 5                    4C  CC */
	PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 6 (Right)") PORT_CODE(KEYCODE_6_PAD) PORT_CODE(KEYCODE_RIGHT ) /* Keypad 6  (Right arrow)     4D  CD */
	PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP +") PORT_CODE(KEYCODE_PLUS_PAD)     /* Keypad +                    4E  CE */
	PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 1 (End)") PORT_CODE(KEYCODE_1_PAD) PORT_CODE(KEYCODE_END )   /* Keypad 1  (End)             4F  CF */

	PORT_START("pc_keyboard_5")
	PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 2 (Down)") PORT_CODE(KEYCODE_2_PAD) PORT_CODE(KEYCODE_DOWN )   /* Keypad 2  (Down arrow)      50  D0 */
	PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 3 (PgDn)") PORT_CODE(KEYCODE_3_PAD) PORT_CODE(KEYCODE_PGDN )   /* Keypad 3  (PgDn)            51  D1 */
	PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 0 (Ins)") PORT_CODE(KEYCODE_0_PAD) PORT_CODE(KEYCODE_INSERT ) /* Keypad 0  (Ins)             52  D2 */
	PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP . (Del)") PORT_CODE(KEYCODE_DEL_PAD) PORT_CODE(KEYCODE_DEL )    /* Keypad .  (Del)             53  D3 */
	PORT_BIT ( 0x0030, 0x0000, IPT_UNUSED )
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(84/102)\\") PORT_CODE(KEYCODE_BACKSLASH2)      /* Backslash 2                 56  D6 */
	PORT_BIT ( 0xff80, 0x0000, IPT_UNUSED )
INPUT_PORTS_END

INPUT_PORTS_START( at_keyboard )
	PORT_START("pc_keyboard_0")
	PORT_BIT ( 0x0001, 0x0000, IPT_UNUSED )     /* unused scancode 0 */
	PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) /* Esc                         01  81 */
	PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) /* 1                           02  82 */
	PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2) /* 2                           03  83 */
	PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) /* 3                           04  84 */
	PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) /* 4                           05  85 */
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) /* 5                           06  86 */
	PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6) /* 6                           07  87 */
	PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7) /* 7                           08  88 */
	PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8) /* 8                           09  89 */
	PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9) /* 9                           0A  8A */
	PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0) /* 0                           0B  8B */
	PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) /* -                           0C  8C */
	PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) /* =                           0D  8D */
	PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("<--") PORT_CODE(KEYCODE_BACKSPACE) /* Backspace                   0E  8E */
	PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) /* Tab                         0F  8F */

	PORT_START("pc_keyboard_1")
	PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) /* Q                           10  90 */
	PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) /* W                           11  91 */
	PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) /* E                           12  92 */
	PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) /* R                           13  93 */
	PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) /* T                           14  94 */
	PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) /* Y                           15  95 */
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) /* U                           16  96 */
	PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) /* I                           17  97 */
	PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) /* O                           18  98 */
	PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) /* P                           19  99 */
	PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) /* [                           1A  9A */
	PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) /* ]                           1B  9B */
	PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) /* Enter                       1C  9C */
	PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L-Ctrl") PORT_CODE(KEYCODE_LCONTROL) /* Left Ctrl                   1D  9D */
	PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) /* A                           1E  9E */
	PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) /* S                           1F  9F */

	PORT_START("pc_keyboard_2")
	PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) /* D                           20  A0 */
	PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) /* F                           21  A1 */
	PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) /* G                           22  A2 */
	PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) /* H                           23  A3 */
	PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) /* J                           24  A4 */
	PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) /* K                           25  A5 */
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) /* L                           26  A6 */
	PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON) /* ;                           27  A7 */
	PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE) /* '                           28  A8 */
	PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("` ~") PORT_CODE(KEYCODE_TILDE) /* `                           29  A9 */
	PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L-Shift") PORT_CODE(KEYCODE_LSHIFT) /* Left Shift                  2A  AA */
	PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) /* \                           2B  AB */
	PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) /* Z                           2C  AC */
	PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) /* X                           2D  AD */
	PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) /* C                           2E  AE */
	PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) /* V                           2F  AF */

	PORT_START("pc_keyboard_3")
	PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) /* B                           30  B0 */
	PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) /* N                           31  B1 */
	PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) /* M                           32  B2 */
	PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) /* ,                           33  B3 */
	PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) /* .                           34  B4 */
	PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) /* /                           35  B5 */
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R-Shift") PORT_CODE(KEYCODE_RSHIFT) /* Right Shift                 36  B6 */
	PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP * (PrtScr)") PORT_CODE(KEYCODE_ASTERISK    ) /* Keypad *  (PrtSc)           37  B7 */
	PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Alt") PORT_CODE(KEYCODE_LALT) /* Left Alt                    38  B8 */
	PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) /* Space                       39  B9 */
	PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK) /* Caps Lock                   3A  BA */
	PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) /* F1                          3B  BB */
	PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) /* F2                          3C  BC */
	PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) /* F3                          3D  BD */
	PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) /* F4                          3E  BE */
	PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) /* F5                          3F  BF */

	PORT_START("pc_keyboard_4")
	PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) /* F6                          40  C0 */
	PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) /* F7                          41  C1 */
	PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) /* F8                          42  C2 */
	PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) /* F9                          43  C3 */
	PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) /* F10                         44  C4 */
	PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("NumLock") PORT_CODE(KEYCODE_NUMLOCK) /* Num Lock                    45  C5 */
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ScrLock") PORT_CODE(KEYCODE_SCRLOCK) /* Scroll Lock                 46  C6 */
	PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 7 (Home)") PORT_CODE(KEYCODE_7_PAD       ) /* Keypad 7  (Home)            47  C7 */
	PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 8 (Up)") PORT_CODE(KEYCODE_8_PAD       ) /* Keypad 8  (Up arrow)        48  C8 */
	PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 9 (PgUp)") PORT_CODE(KEYCODE_9_PAD       ) /* Keypad 9  (PgUp)            49  C9 */
	PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP -") PORT_CODE(KEYCODE_MINUS_PAD) /* Keypad -                    4A  CA */
	PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 4 (Left)") PORT_CODE(KEYCODE_4_PAD       ) /* Keypad 4  (Left arrow)      4B  CB */
	PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 5") PORT_CODE(KEYCODE_5_PAD) /* Keypad 5                    4C  CC */
	PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 6 (Right)") PORT_CODE(KEYCODE_6_PAD       ) /* Keypad 6  (Right arrow)     4D  CD */
	PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP +") PORT_CODE(KEYCODE_PLUS_PAD) /* Keypad +                    4E  CE */
	PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 1 (End)") PORT_CODE(KEYCODE_1_PAD       ) /* Keypad 1  (End)             4F  CF */

	PORT_START("pc_keyboard_5")
	PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 2 (Down)") PORT_CODE(KEYCODE_2_PAD       ) /* Keypad 2  (Down arrow)      50  D0 */
	PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 3 (PgDn)") PORT_CODE(KEYCODE_3_PAD       ) /* Keypad 3  (PgDn)            51  D1 */
	PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP 0 (Ins)") PORT_CODE(KEYCODE_0_PAD       ) /* Keypad 0  (Ins)             52  D2 */
	PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("KP . (Del)") PORT_CODE(KEYCODE_DEL_PAD     ) /* Keypad .  (Del)             53  D3 */
	PORT_BIT ( 0x0030, 0x0000, IPT_UNUSED )
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(84/102)\\") PORT_CODE(KEYCODE_BACKSLASH2) /* Backslash 2                 56  D6 */
	PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)F11") PORT_CODE(KEYCODE_F11) /* F11                         57  D7 */
	PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)F12") PORT_CODE(KEYCODE_F12) /* F12                         58  D8 */
	PORT_BIT ( 0xfe00, 0x0000, IPT_UNUSED )

	PORT_START("pc_keyboard_6")
	PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)KP Enter") PORT_CODE(KEYCODE_ENTER_PAD) /* PAD Enter                   60  e0 */
	PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Right Control") PORT_CODE(KEYCODE_RCONTROL) /* Right Control               61  e1 */
	PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)KP /") PORT_CODE(KEYCODE_SLASH_PAD) /* PAD Slash                   62  e2 */
	PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)PRTSCR") PORT_CODE(KEYCODE_PRTSCR) /* Print Screen                63  e3 */
	PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)ALTGR") PORT_CODE(KEYCODE_RALT) /* ALTGR                       64  e4 */
	PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Home") PORT_CODE(KEYCODE_HOME) /* Home                        66  e6 */
	PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Cursor Up") PORT_CODE(KEYCODE_UP) /* Up                          67  e7 */
	PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Page Up") PORT_CODE(KEYCODE_PGUP) /* Page Up                     68  e8 */
	PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Cursor Left") PORT_CODE(KEYCODE_LEFT) /* Left                        69  e9 */
	PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Cursor Right") PORT_CODE(KEYCODE_RIGHT) /* Right                       6a  ea */
	PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)End") PORT_CODE(KEYCODE_END) /* End                         6b  eb */
	PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Cursor Down") PORT_CODE(KEYCODE_DOWN) /* Down                        6c  ec */
	PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Page Down") PORT_CODE(KEYCODE_PGDN) /* Page Down                   6d  ed */
	PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Insert") PORT_CODE(KEYCODE_INSERT) /* Insert                      6e  ee */
	PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Delete") PORT_CODE(KEYCODE_DEL) /* Delete                      6f  ef */
	PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(MF2)Pause") PORT_CODE(KEYCODE_PAUSE) /* Pause                       65  e5 */

	PORT_START("pc_keyboard_7")
	PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Print Screen") PORT_CODE(KEYCODE_PRTSCR) /* Print Screen alternate      77  f7 */
	PORT_BIT ( 0xfffe, 0x0000, IPT_UNUSED )
INPUT_PORTS_END

/***************************************************************************
  Inputx stuff
***************************************************************************/

bool pc_keyboard_device::accept_char(char32_t ch)
{
	return unicode_char_to_at_keycode(ch) != 0;
}



bool pc_keyboard_device::charqueue_empty()
{
	return queue_size() == 0;
}
