/* keyboard.c: Routines for dealing with the Spectrum's keyboard Copyright (c) 1999-2016 Philip Kendall This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Author contact information: E-mail: philip-fuse@shadowmagic.org.uk */ #include #ifdef HAVE_LIB_GLIB #include #endif /* #ifdef HAVE_LIB_GLIB */ #include #include "infrastructure/startup_manager.h" #include "keyboard.h" #include "ui/ui.h" /* Bit masks for each of the eight keyboard half-rows; `AND' the selected ones of these to get the value to return */ libspectrum_byte keyboard_return_values[8]; /* The hash used for storing the UI -> Fuse input layer key mappings */ static GHashTable *keysyms_hash; struct spectrum_keys_wrapper { input_key input; keyboard_spectrum_keys_t spectrum; }; /* Which Spectrum keys should be pressed for each key passed from the Fuse input layer */ static struct spectrum_keys_wrapper spectrum_keys_table[] = { { INPUT_KEY_Escape, { KEYBOARD_1, KEYBOARD_Caps } }, { INPUT_KEY_1, { KEYBOARD_1, KEYBOARD_NONE } }, { INPUT_KEY_2, { KEYBOARD_2, KEYBOARD_NONE } }, { INPUT_KEY_3, { KEYBOARD_3, KEYBOARD_NONE } }, { INPUT_KEY_4, { KEYBOARD_4, KEYBOARD_NONE } }, { INPUT_KEY_5, { KEYBOARD_5, KEYBOARD_NONE } }, { INPUT_KEY_6, { KEYBOARD_6, KEYBOARD_NONE } }, { INPUT_KEY_7, { KEYBOARD_7, KEYBOARD_NONE } }, { INPUT_KEY_8, { KEYBOARD_8, KEYBOARD_NONE } }, { INPUT_KEY_9, { KEYBOARD_9, KEYBOARD_NONE } }, { INPUT_KEY_0, { KEYBOARD_0, KEYBOARD_NONE } }, { INPUT_KEY_minus, { KEYBOARD_j, KEYBOARD_Symbol } }, { INPUT_KEY_equal, { KEYBOARD_l, KEYBOARD_Symbol } }, { INPUT_KEY_BackSpace, { KEYBOARD_0, KEYBOARD_Caps } }, { INPUT_KEY_Tab, { KEYBOARD_Caps, KEYBOARD_Symbol } }, { INPUT_KEY_q, { KEYBOARD_q, KEYBOARD_NONE } }, { INPUT_KEY_w, { KEYBOARD_w, KEYBOARD_NONE } }, { INPUT_KEY_e, { KEYBOARD_e, KEYBOARD_NONE } }, { INPUT_KEY_r, { KEYBOARD_r, KEYBOARD_NONE } }, { INPUT_KEY_t, { KEYBOARD_t, KEYBOARD_NONE } }, { INPUT_KEY_y, { KEYBOARD_y, KEYBOARD_NONE } }, { INPUT_KEY_u, { KEYBOARD_u, KEYBOARD_NONE } }, { INPUT_KEY_i, { KEYBOARD_i, KEYBOARD_NONE } }, { INPUT_KEY_o, { KEYBOARD_o, KEYBOARD_NONE } }, { INPUT_KEY_p, { KEYBOARD_p, KEYBOARD_NONE } }, { INPUT_KEY_Caps_Lock, { KEYBOARD_2, KEYBOARD_Caps } }, { INPUT_KEY_a, { KEYBOARD_a, KEYBOARD_NONE } }, { INPUT_KEY_s, { KEYBOARD_s, KEYBOARD_NONE } }, { INPUT_KEY_d, { KEYBOARD_d, KEYBOARD_NONE } }, { INPUT_KEY_f, { KEYBOARD_f, KEYBOARD_NONE } }, { INPUT_KEY_g, { KEYBOARD_g, KEYBOARD_NONE } }, { INPUT_KEY_h, { KEYBOARD_h, KEYBOARD_NONE } }, { INPUT_KEY_j, { KEYBOARD_j, KEYBOARD_NONE } }, { INPUT_KEY_k, { KEYBOARD_k, KEYBOARD_NONE } }, { INPUT_KEY_l, { KEYBOARD_l, KEYBOARD_NONE } }, { INPUT_KEY_semicolon, { KEYBOARD_o, KEYBOARD_Symbol } }, { INPUT_KEY_apostrophe, { KEYBOARD_7, KEYBOARD_Symbol } }, { INPUT_KEY_numbersign, { KEYBOARD_3, KEYBOARD_Symbol } }, { INPUT_KEY_Return, { KEYBOARD_Enter, KEYBOARD_NONE } }, { INPUT_KEY_Shift_L, { KEYBOARD_NONE, KEYBOARD_Caps } }, { INPUT_KEY_z, { KEYBOARD_z, KEYBOARD_NONE } }, { INPUT_KEY_x, { KEYBOARD_x, KEYBOARD_NONE } }, { INPUT_KEY_c, { KEYBOARD_c, KEYBOARD_NONE } }, { INPUT_KEY_v, { KEYBOARD_v, KEYBOARD_NONE } }, { INPUT_KEY_b, { KEYBOARD_b, KEYBOARD_NONE } }, { INPUT_KEY_n, { KEYBOARD_n, KEYBOARD_NONE } }, { INPUT_KEY_m, { KEYBOARD_m, KEYBOARD_NONE } }, { INPUT_KEY_comma, { KEYBOARD_n, KEYBOARD_Symbol } }, { INPUT_KEY_period, { KEYBOARD_m, KEYBOARD_Symbol } }, { INPUT_KEY_slash, { KEYBOARD_v, KEYBOARD_Symbol } }, { INPUT_KEY_Shift_R, { KEYBOARD_NONE, KEYBOARD_Caps } }, { INPUT_KEY_asterisk, { KEYBOARD_b, KEYBOARD_Symbol } }, { INPUT_KEY_dollar, { KEYBOARD_4, KEYBOARD_Symbol } }, { INPUT_KEY_exclam, { KEYBOARD_1, KEYBOARD_Symbol } }, { INPUT_KEY_less, { KEYBOARD_r, KEYBOARD_Symbol } }, { INPUT_KEY_parenright, { KEYBOARD_9, KEYBOARD_Symbol } }, { INPUT_KEY_colon, { KEYBOARD_z, KEYBOARD_Symbol } }, { INPUT_KEY_plus, { KEYBOARD_k, KEYBOARD_Symbol } }, { INPUT_KEY_Control_L, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Alt_L, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Meta_L, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Super_L, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Hyper_L, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_space, { KEYBOARD_space, KEYBOARD_NONE } }, { INPUT_KEY_Hyper_R, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Super_R, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Meta_R, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Alt_R, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Control_R, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Mode_switch, { KEYBOARD_NONE, KEYBOARD_Symbol } }, { INPUT_KEY_Left, { KEYBOARD_5, KEYBOARD_NONE } }, { INPUT_KEY_Down, { KEYBOARD_6, KEYBOARD_NONE } }, { INPUT_KEY_Up, { KEYBOARD_7, KEYBOARD_NONE } }, { INPUT_KEY_Right, { KEYBOARD_8, KEYBOARD_NONE } }, { INPUT_KEY_KP_Enter, { KEYBOARD_Enter, KEYBOARD_NONE } }, { INPUT_KEY_NONE, { KEYBOARD_NONE, KEYBOARD_NONE } } /* End marker */ }; static GHashTable *spectrum_keys; /* When each Spectrum key is pressed, twiddle this {port,bit} pair in `keyboard_return_values'. */ struct key_bit { int port; libspectrum_byte bit; }; struct key_info { keyboard_key_name key; struct key_bit bit; }; static struct key_info keyboard_data_table[] = { { KEYBOARD_1, { 3, 0x01 } }, { KEYBOARD_2, { 3, 0x02 } }, { KEYBOARD_3, { 3, 0x04 } }, { KEYBOARD_4, { 3, 0x08 } }, { KEYBOARD_5, { 3, 0x10 } }, { KEYBOARD_6, { 4, 0x10 } }, { KEYBOARD_7, { 4, 0x08 } }, { KEYBOARD_8, { 4, 0x04 } }, { KEYBOARD_9, { 4, 0x02 } }, { KEYBOARD_0, { 4, 0x01 } }, { KEYBOARD_q, { 2, 0x01 } }, { KEYBOARD_w, { 2, 0x02 } }, { KEYBOARD_e, { 2, 0x04 } }, { KEYBOARD_r, { 2, 0x08 } }, { KEYBOARD_t, { 2, 0x10 } }, { KEYBOARD_y, { 5, 0x10 } }, { KEYBOARD_u, { 5, 0x08 } }, { KEYBOARD_i, { 5, 0x04 } }, { KEYBOARD_o, { 5, 0x02 } }, { KEYBOARD_p, { 5, 0x01 } }, { KEYBOARD_a, { 1, 0x01 } }, { KEYBOARD_s, { 1, 0x02 } }, { KEYBOARD_d, { 1, 0x04 } }, { KEYBOARD_f, { 1, 0x08 } }, { KEYBOARD_g, { 1, 0x10 } }, { KEYBOARD_h, { 6, 0x10 } }, { KEYBOARD_j, { 6, 0x08 } }, { KEYBOARD_k, { 6, 0x04 } }, { KEYBOARD_l, { 6, 0x02 } }, { KEYBOARD_Enter, { 6, 0x01 } }, { KEYBOARD_Caps, { 0, 0x01 } }, { KEYBOARD_z, { 0, 0x02 } }, { KEYBOARD_x, { 0, 0x04 } }, { KEYBOARD_c, { 0, 0x08 } }, { KEYBOARD_v, { 0, 0x10 } }, { KEYBOARD_b, { 7, 0x10 } }, { KEYBOARD_n, { 7, 0x08 } }, { KEYBOARD_m, { 7, 0x04 } }, { KEYBOARD_Symbol, { 7, 0x02 } }, { KEYBOARD_space, { 7, 0x01 } }, { KEYBOARD_NONE, { 0, 0x00 } } /* End marker */ }; /* The hash used for storing keyboard_data_table */ static GHashTable *keyboard_data; /* A textual name for each key */ struct key_text_t { keyboard_key_name key; const char *text; }; struct key_text_t key_text_table[] = { { KEYBOARD_NONE, "Nothing" }, { KEYBOARD_space, "Space" }, { KEYBOARD_0, "0" }, { KEYBOARD_1, "1" }, { KEYBOARD_2, "2" }, { KEYBOARD_3, "3" }, { KEYBOARD_4, "4" }, { KEYBOARD_5, "5" }, { KEYBOARD_6, "6" }, { KEYBOARD_7, "7" }, { KEYBOARD_8, "8" }, { KEYBOARD_9, "9" }, { KEYBOARD_a, "A" }, { KEYBOARD_b, "B" }, { KEYBOARD_c, "C" }, { KEYBOARD_d, "D" }, { KEYBOARD_e, "E" }, { KEYBOARD_f, "F" }, { KEYBOARD_g, "G" }, { KEYBOARD_h, "H" }, { KEYBOARD_i, "I" }, { KEYBOARD_j, "J" }, { KEYBOARD_k, "K" }, { KEYBOARD_l, "L" }, { KEYBOARD_m, "M" }, { KEYBOARD_n, "N" }, { KEYBOARD_o, "O" }, { KEYBOARD_p, "P" }, { KEYBOARD_q, "Q" }, { KEYBOARD_r, "R" }, { KEYBOARD_s, "S" }, { KEYBOARD_t, "T" }, { KEYBOARD_u, "U" }, { KEYBOARD_v, "V" }, { KEYBOARD_w, "W" }, { KEYBOARD_x, "X" }, { KEYBOARD_y, "Y" }, { KEYBOARD_z, "Z" }, { KEYBOARD_Enter, "Enter" }, { KEYBOARD_Caps, "Caps Shift" }, { KEYBOARD_Symbol, "Symbol Shift" }, { KEYBOARD_JOYSTICK_FIRE, "Joystick Fire" }, { KEYBOARD_NONE, NULL }, /* End marker */ }; static GHashTable *key_text; static int keyboard_init( void *context ) { struct key_info *ptr; struct spectrum_keys_wrapper *ptr2; keysyms_map_t *ptr3; struct key_text_t *ptr4; keyboard_release_all(); keyboard_data = g_hash_table_new( g_int_hash, g_int_equal ); for( ptr = keyboard_data_table; ptr->key != KEYBOARD_NONE; ptr++ ) g_hash_table_insert( keyboard_data, &( ptr->key ), &( ptr->bit ) ); spectrum_keys = g_hash_table_new( g_int_hash, g_int_equal ); for( ptr2 = spectrum_keys_table; ptr2->input != INPUT_KEY_NONE; ptr2++ ) g_hash_table_insert( spectrum_keys, &( ptr2->input ), &( ptr2->spectrum ) ); keysyms_hash = g_hash_table_new( g_int_hash, g_int_equal ); for( ptr3 = keysyms_map; ptr3->ui; ptr3++ ) g_hash_table_insert( keysyms_hash, &( ptr3->ui ), &( ptr3->fuse ) ); key_text = g_hash_table_new( g_int_hash, g_int_equal ); for( ptr4 = key_text_table; ptr4->text != NULL; ptr4++ ) g_hash_table_insert( key_text, &( ptr4->key ), &( ptr4->text ) ); return 0; } static void keyboard_end( void ) { g_hash_table_destroy( keyboard_data ); g_hash_table_destroy( spectrum_keys ); g_hash_table_destroy( keysyms_hash ); g_hash_table_destroy( key_text ); } void keyboard_register_startup( void ) { startup_manager_module dependencies[] = { STARTUP_MANAGER_MODULE_LIBSPECTRUM, STARTUP_MANAGER_MODULE_SETUID }; startup_manager_register( STARTUP_MANAGER_MODULE_KEYBOARD, dependencies, ARRAY_SIZE( dependencies ), keyboard_init, keyboard_end, NULL ); } libspectrum_byte keyboard_read( libspectrum_byte porth ) { libspectrum_byte data = 0xff; int i; for( i=0; i<8; i++,porth>>=1 ) { if(! (porth&0x01) ) data &= keyboard_return_values[i]; } return data; } void keyboard_press( keyboard_key_name key ) { struct key_bit *ptr; ptr = g_hash_table_lookup( keyboard_data, &key ); if( ptr ) keyboard_return_values[ ptr->port ] &= ~( ptr->bit ); } void keyboard_release( keyboard_key_name key ) { struct key_bit *ptr; ptr = g_hash_table_lookup( keyboard_data, &key ); if( ptr ) keyboard_return_values[ ptr->port ] |= ptr->bit; } int keyboard_release_all( void ) { int i; for( i=0; i<8; i++ ) keyboard_return_values[i] = 0xff; return 0; } const keyboard_spectrum_keys_t* keyboard_get_spectrum_keys( input_key keysym ) { return g_hash_table_lookup( spectrum_keys, &keysym ); } input_key keysyms_remap( libspectrum_dword ui_keysym ) { const input_key *ptr; ptr = g_hash_table_lookup( keysyms_hash, &ui_keysym ); return ptr ? *ptr : INPUT_KEY_NONE; } const char* keyboard_key_text( keyboard_key_name key ) { const char **ptr; ptr = g_hash_table_lookup( key_text, &key ); return ptr ? *ptr : "[Unknown key]"; } libspectrum_byte keyboard_simulate_keypress( libspectrum_byte porth, keyboard_key_name key ) { libspectrum_byte r = 0xff; struct key_bit *data; data = g_hash_table_lookup( keyboard_data, &key ); if( data ) { libspectrum_byte mask = (1 << data->port); if( !(porth & mask) ) { r &= ~data->bit; } } return r; }