diff --git a/SheepShaver/src/Unix/prefs_editor_gtk.cpp b/SheepShaver/src/Unix/prefs_editor_gtk.cpp index e6626ddb..ad92ee88 100644 --- a/SheepShaver/src/Unix/prefs_editor_gtk.cpp +++ b/SheepShaver/src/Unix/prefs_editor_gtk.cpp @@ -44,6 +44,7 @@ static bool start_clicked = true; // Return value of PrefsEditor() function // Prototypes static void create_volumes_pane(GtkWidget *top); static void create_graphics_pane(GtkWidget *top); +static void create_input_pane(GtkWidget *top); static void create_serial_pane(GtkWidget *top); static void create_memory_pane(GtkWidget *top); static void read_settings(void); @@ -170,6 +171,11 @@ static GtkWidget *make_entry(GtkWidget *top, int label_id, const char *prefs_ite return entry; } +static char *get_file_entry_path(GtkWidget *entry) +{ + return gtk_entry_get_text(GTK_ENTRY(entry)); +} + static GtkWidget *make_checkbox(GtkWidget *top, int label_id, const char *prefs_item, GtkSignalFunc func) { GtkWidget *button = gtk_check_button_new_with_label(GetString(label_id)); @@ -313,6 +319,7 @@ bool PrefsEditor(void) create_volumes_pane(notebook); create_graphics_pane(notebook); + create_input_pane(notebook); create_serial_pane(notebook); create_memory_pane(notebook); @@ -630,6 +637,50 @@ static void create_graphics_pane(GtkWidget *top) } +/* + * "Input" pane + */ + +static GtkWidget *w_keycode_file; + +// Set sensitivity of widgets +static void set_input_sensitive(void) +{ + gtk_widget_set_sensitive(w_keycode_file, PrefsFindBool("keycodes")); +} + +// "Use Raw Keycodes" button toggled +static void tb_keycodes(GtkWidget *widget) +{ + PrefsReplaceBool("keycodes", GTK_TOGGLE_BUTTON(widget)->active); + set_input_sensitive(); +} + +// Read settings from widgets and set preferences +static void read_input_settings(void) +{ + const char *str = get_file_entry_path(w_keycode_file); + if (str && strlen(str)) + PrefsReplaceString("keycodefile", str); + else + PrefsRemoveItem("keycodefile"); +} + +// Create "Input" pane +static void create_input_pane(GtkWidget *top) +{ + GtkWidget *box, *hbox, *menu, *label; + GtkObject *adj; + + box = make_pane(top, STR_INPUT_PANE_TITLE); + + make_checkbox(box, STR_KEYCODES_CTRL, "keycodes", GTK_SIGNAL_FUNC(tb_keycodes)); + w_keycode_file = make_entry(box, STR_KEYCODE_FILE_CTRL, "keycodefile"); + + set_input_sensitive(); +} + + /* * "Serial/Network" pane */ diff --git a/SheepShaver/src/Unix/prefs_unix.cpp b/SheepShaver/src/Unix/prefs_unix.cpp index aad13296..1d2583e6 100644 --- a/SheepShaver/src/Unix/prefs_unix.cpp +++ b/SheepShaver/src/Unix/prefs_unix.cpp @@ -30,6 +30,8 @@ // Platform-specific preferences items prefs_desc platform_prefs_items[] = { {"ether", TYPE_STRING, false, "device name of Mac ethernet adapter"}, + {"keycodes", TYPE_BOOLEAN, false, "use keycodes rather than keysyms to decode keyboard"}, + {"keycodefile", TYPE_STRING, false, "path of keycode translation file"}, {NULL, TYPE_END, false, NULL} // End of list }; @@ -91,6 +93,7 @@ void SavePrefs(void) void AddPlatformPrefsDefaults(void) { + PrefsAddBool("keycodes", false); PrefsReplaceString("extfs", "/"); PrefsAddInt32("windowmodes", 3); PrefsAddInt32("screenmodes", 0x3f); diff --git a/SheepShaver/src/Unix/user_strings_unix.cpp b/SheepShaver/src/Unix/user_strings_unix.cpp index 3cd508a5..f85bd24d 100644 --- a/SheepShaver/src/Unix/user_strings_unix.cpp +++ b/SheepShaver/src/Unix/user_strings_unix.cpp @@ -55,6 +55,8 @@ user_string_def platform_strings[] = { {STR_AUDIO_FORMAT_WARN, "/dev/dsp doesn't support signed 16 bit format. Audio output will be disabled."}, {STR_SCSI_DEVICE_OPEN_WARN, "Cannot open %s (%s). SCSI Manager access to this device will be disabled."}, {STR_SCSI_DEVICE_NOT_SCSI_WARN, "%s doesn't seem to comply to the Generic SCSI API. SCSI Manager access to this device will be disabled."}, + {STR_KEYCODE_FILE_WARN, "Cannot open keycode translation file %s (%s)."}, + {STR_KEYCODE_VENDOR_WARN, "Cannot find vendor '%s' in keycode translation file %s."}, {STR_PREFS_MENU_FILE_GTK, "/_File"}, {STR_PREFS_ITEM_START_GTK, "/File/_Start SheepShaver"}, {STR_PREFS_ITEM_ZAP_PRAM_GTK, "/File/_Zap PRAM File"}, @@ -62,6 +64,9 @@ user_string_def platform_strings[] = { {STR_PREFS_ITEM_QUIT_GTK, "/File/_Quit SheepShaver"}, {STR_HELP_MENU_GTK, "/_Help"}, {STR_HELP_ITEM_ABOUT_GTK, "/Help/_About SheepShaver"}, + {STR_INPUT_PANE_TITLE, "Keyboard"}, + {STR_KEYCODES_CTRL, "Use Raw Keycodes"}, + {STR_KEYCODE_FILE_CTRL, "Keycode Translation File"}, {STR_SUSPEND_WINDOW_TITLE, "SheepShaver suspended. Press Space to reactivate."}, {STR_VOSF_INIT_ERR, "Cannot initialize Video on SEGV signals."}, diff --git a/SheepShaver/src/Unix/user_strings_unix.h b/SheepShaver/src/Unix/user_strings_unix.h index afab987b..bc432fd8 100644 --- a/SheepShaver/src/Unix/user_strings_unix.h +++ b/SheepShaver/src/Unix/user_strings_unix.h @@ -37,6 +37,8 @@ enum { STR_NO_XSERVER_ERR, STR_NO_XVISUAL_ERR, STR_UNSUPP_DEPTH_ERR, + STR_VOSF_INIT_ERR, + STR_PROC_CPUINFO_WARN, STR_NO_SHEEP_NET_DRIVER_WARN, STR_SHEEP_NET_ATTACH_WARN, @@ -46,6 +48,9 @@ enum { STR_AUDIO_FORMAT_WARN, STR_SCSI_DEVICE_OPEN_WARN, STR_SCSI_DEVICE_NOT_SCSI_WARN, + STR_KEYCODE_FILE_WARN, + STR_KEYCODE_VENDOR_WARN, + STR_PREFS_MENU_FILE_GTK, STR_PREFS_ITEM_START_GTK, STR_PREFS_ITEM_ZAP_PRAM_GTK, @@ -54,7 +59,9 @@ enum { STR_HELP_MENU_GTK, STR_HELP_ITEM_ABOUT_GTK, STR_SUSPEND_WINDOW_TITLE, - STR_VOSF_INIT_ERR + STR_INPUT_PANE_TITLE, + STR_KEYCODES_CTRL, + STR_KEYCODE_FILE_CTRL }; #endif diff --git a/SheepShaver/src/Unix/video_x.cpp b/SheepShaver/src/Unix/video_x.cpp index d834f42b..5fed2270 100644 --- a/SheepShaver/src/Unix/video_x.cpp +++ b/SheepShaver/src/Unix/video_x.cpp @@ -18,15 +18,28 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "sysdeps.h" + #include #include #include #include #include #include -#include +#include + +#ifdef HAVE_PTHREADS +# include +#endif + +#ifdef ENABLE_XF86_DGA +#include +#endif + +#ifdef ENABLE_XF86_VIDMODE +# include +#endif -#include "sysdeps.h" #include "main.h" #include "adb.h" #include "prefs.h" @@ -38,14 +51,9 @@ #define DEBUG 0 #include "debug.h" -#ifdef ENABLE_XF86_DGA -#include -#endif - -#ifdef ENABLE_XF86_VIDMODE -#include -#endif +// Constants +const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes"; // Global variables static int32 frame_skip; @@ -74,6 +82,8 @@ static bool emerg_quit = false; // Flag: Ctrl-Esc pressed, emergency quit req static bool emul_suspended = false; // Flag: emulator suspended static Window suspend_win; // "Suspend" window static void *fb_save = NULL; // Saved frame buffer for suspend +static bool use_keycodes = false; // Flag: Use keycodes rather than keysyms +static int keycode_table[256]; // X keycode -> Mac keycode translation table // X11 variables static int screen; // Screen number @@ -534,6 +544,71 @@ static void close_display(void) * Initialization */ +// Init keycode translation table +static void keycode_init(void) +{ + bool use_kc = PrefsFindBool("keycodes"); + if (use_kc) { + + // Get keycode file path from preferences + const char *kc_path = PrefsFindString("keycodefile"); + + // Open keycode table + FILE *f = fopen(kc_path ? kc_path : KEYCODE_FILE_NAME, "r"); + if (f == NULL) { + char str[256]; + sprintf(str, GetString(STR_KEYCODE_FILE_WARN), kc_path ? kc_path : KEYCODE_FILE_NAME, strerror(errno)); + WarningAlert(str); + return; + } + + // Default translation table + for (int i=0; i<256; i++) + keycode_table[i] = -1; + + // Search for server vendor string, then read keycodes + const char *vendor = ServerVendor(x_display); + bool vendor_found = false; + char line[256]; + while (fgets(line, 255, f)) { + // Read line + int len = strlen(line); + if (len == 0) + continue; + line[len-1] = 0; + + // Comments begin with "#" or ";" + if (line[0] == '#' || line[0] == ';' || line[0] == 0) + continue; + + if (vendor_found) { + // Read keycode + int x_code, mac_code; + if (sscanf(line, "%d %d", &x_code, &mac_code) == 2) + keycode_table[x_code & 0xff] = mac_code; + else + break; + } else { + // Search for vendor string + if (strstr(vendor, line) == vendor) + vendor_found = true; + } + } + + // Keycode file completely read + fclose(f); + use_keycodes = vendor_found; + + // Vendor not found? Then display warning + if (!vendor_found) { + char str[256]; + sprintf(str, GetString(STR_KEYCODE_VENDOR_WARN), vendor, kc_path ? kc_path : KEYCODE_FILE_NAME); + WarningAlert(str); + return; + } + } +} + static void add_mode(VideoInfo *&p, uint32 allow, uint32 test, long apple_mode, long apple_id, int type) { if (allow & test) { @@ -607,6 +682,9 @@ bool VideoInit(void) local_X11 = (strncmp(XDisplayName(x_display_name), ":", 1) == 0) || (strncmp(XDisplayName(x_display_name), "unix:", 5) == 0); + // Init keycode translation + keycode_init(); + // Init variables private_data = NULL; cur_mode = 0; // Window 640x480 @@ -1078,14 +1156,14 @@ static int kc_decode(KeySym ks) return -1; } -static int event2keycode(XKeyEvent *ev) +static int event2keycode(XKeyEvent &ev) { KeySym ks; int as; int i = 0; do { - ks = XLookupKeysym(ev, i++); + ks = XLookupKeysym(&ev, i++); as = kc_decode(ks); if (as != -1) return as; @@ -1128,8 +1206,10 @@ static void handle_events(void) // Keyboard case KeyPress: { - int code; - if ((code = event2keycode((XKeyEvent *)&event)) != -1) { + int code = event2keycode(event.xkey); + if (use_keycodes && code != -1) + code = keycode_table[event.xkey.keycode & 0xff]; + if (code != -1) { if (!emul_suspended) { ADBKeyDown(code); if (code == 0x36) @@ -1142,8 +1222,10 @@ static void handle_events(void) break; } case KeyRelease: { - int code; - if ((code = event2keycode((XKeyEvent *)&event)) != -1) { + int code = event2keycode(event.xkey); + if (use_keycodes && code != 1) + code = keycode_table[event.xkey.keycode & 0xff]; + if (code != -1) { ADBKeyUp(code); if (code == 0x36) ctrl_down = false;