diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index 0fe5bc9..f22e153 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -53,6 +53,7 @@ + @@ -90,6 +91,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index e783c6e..577c994 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -133,6 +133,9 @@ Source Files + + Source Files + @@ -267,5 +270,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/cheats.cpp b/cheats.cpp new file mode 100644 index 0000000..5e86f7c --- /dev/null +++ b/cheats.cpp @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hardware.h" +#include "file_io.h" +#include "user_io.h" +#include "fpga_io.h" +#include "miniz_zip.h" +#include "osd.h" +#include "cheats.h" + +struct cheat_rec_t +{ + char enabled; + char name[256]; +}; + +typedef std::vector CheatVector; +static CheatVector cheats; + +static int iSelectedEntry = 0; +static int iFirstEntry = 0; +static int loaded = 0; + +struct CheatComp +{ + bool operator()(const cheat_rec_t& ce1, const cheat_rec_t& ce2) + { + int len1 = strlen(ce1.name); + int len2 = strlen(ce2.name); + + int len = (len1 < len2) ? len1 : len2; + int ret = strncasecmp(ce1.name, ce2.name, len); + if (!ret) + { + return len1 < len2; + } + + return ret < 0; + } +}; + +static char cheat_zip[1024] = {}; + +void cheats_init(char *rom_path) +{ + cheats.clear(); + loaded = 0; + cheat_zip[0] = 0; + + if (!strcasestr(rom_path, ".zip")) + { + sprintf(cheat_zip, "%s/%s", getRootDir(), rom_path); + char *p = strrchr(cheat_zip, '.'); + if (p) *p = 0; + strcat(cheat_zip, ".zip"); + } + + mz_zip_archive _z = {}; + if (!mz_zip_reader_init_file(&_z, cheat_zip, 0)) + { + memset(&_z, 0, sizeof(_z)); + + char *rom_name = strrchr(rom_path, '/'); + if (!rom_name) return; + + sprintf(cheat_zip, "%s/cheats/%s%s", getRootDir(), HomeDir, rom_name); + char *p = strrchr(cheat_zip, '.'); + if (p) *p = 0; + strcat(cheat_zip, ".zip"); + + if (!mz_zip_reader_init_file(&_z, cheat_zip, 0)) + { + printf("no cheat file %s\n", cheat_zip); + return; + } + } + + mz_zip_archive *z = new mz_zip_archive(_z); + for (size_t i = 0; i < mz_zip_reader_get_num_files(z); i++) + { + cheat_rec_t ch = {}; + mz_zip_reader_get_filename(z, i, ch.name, sizeof(ch.name)); + + if (mz_zip_reader_is_file_a_directory(z, i)) + { + continue; + } + + cheats.push_back(ch); + } + + mz_zip_reader_end(z); + delete z; + + std::sort(cheats.begin(), cheats.end(), CheatComp()); + + printf("cheats: %d\n", cheats_available()); + cheats_scan(SCANF_INIT); +} + +int cheats_available() +{ + return cheats.size(); +} + +void cheats_scan(int mode) +{ + if (mode == SCANF_INIT) + { + iFirstEntry = 0; + iSelectedEntry = 0; + } + else + { + if (!cheats_available()) return; + + if (mode == SCANF_END) + { + iSelectedEntry = cheats_available() - 1; + iFirstEntry = iSelectedEntry - OsdGetSize() + 1; + if (iFirstEntry < 0) iFirstEntry = 0; + } + else if (mode == SCANF_NEXT) + { + if (iSelectedEntry + 1 < cheats_available()) // scroll within visible items + { + iSelectedEntry++; + if (iSelectedEntry > iFirstEntry + OsdGetSize() - 1) iFirstEntry = iSelectedEntry - OsdGetSize() + 1; + } + } + else if (mode == SCANF_PREV) + { + if (iSelectedEntry > 0) // scroll within visible items + { + iSelectedEntry--; + if (iSelectedEntry < iFirstEntry) iFirstEntry = iSelectedEntry; + } + } + else if (mode == SCANF_NEXT_PAGE) + { + if (iSelectedEntry < iFirstEntry + OsdGetSize() - 1) + { + iSelectedEntry = iFirstEntry + OsdGetSize() - 1; + if (iSelectedEntry >= cheats_available()) iSelectedEntry = cheats_available() - 1; + } + else + { + iSelectedEntry += OsdGetSize(); + iFirstEntry += OsdGetSize(); + if (iSelectedEntry >= cheats_available()) + { + iSelectedEntry = cheats_available() - 1; + iFirstEntry = iSelectedEntry - OsdGetSize() + 1; + if (iFirstEntry < 0) iFirstEntry = 0; + } + else if (iFirstEntry + OsdGetSize() > cheats_available()) + { + iFirstEntry = cheats_available() - OsdGetSize(); + } + } + } + else if (mode == SCANF_PREV_PAGE) + { + if (iSelectedEntry != iFirstEntry) + { + iSelectedEntry = iFirstEntry; + } + else + { + iFirstEntry -= OsdGetSize(); + if (iFirstEntry < 0) iFirstEntry = 0; + iSelectedEntry = iFirstEntry; + } + } + } +} + +void cheats_scroll_name() +{ + // this function is called periodically when file selection window is displayed + // it checks if predefined period of time has elapsed and scrolls the name if necessary + int len; + int max_len; + static char name[256 + 4]; + + name[0] = 32; + name[1] = cheats[iSelectedEntry].enabled ? 0x1a : 0x1b; + name[2] = 32; + strcpy(name + 3, cheats[iSelectedEntry].name); + + len = strlen(name); // get name length + if (len > 3 && !strncasecmp(name + len - 3, ".gg", 3)) len -= 3; + + max_len = 30; + ScrollText(iSelectedEntry - iFirstEntry, name, 3, len, max_len, 1); +} + +void cheats_print() +{ + int k; + int len; + + static char s[256+4]; + + ScrollReset(); + + for (int i = 0; i < OsdGetSize(); i++) + { + char leftchar = 0; + if (i < cheats_available()) + { + k = iFirstEntry + i; + + s[0] = 32; + s[1] = cheats[k].enabled ? 0x1a : 0x1b; + s[2] = 32; + strcpy(s + 3, cheats[k].name); + + len = strlen(s); // get name length + if (len > 3 && !strncasecmp(s + len - 3, ".gg", 3)) len -= 3; + s[len] = 0; + + if (len > 28) + { + len = 27; // trim display length if longer than 30 characters + s[28] = 22; + } + + s[29] = 0; + + if (!i && k) leftchar = 17; + if ((i == OsdGetSize() - 1) && (k < cheats_available() - 1)) leftchar = 16; + } + else + { + memset(s, ' ', 32); + } + + OsdWriteOffset(i, s, i == (iSelectedEntry - iFirstEntry), 0, 0, leftchar); + } +} + +#define CHEAT_SIZE (128*16) // 128 codes max + +static void cheats_send() +{ + static char filename[1024]; + static uint8_t buff[CHEAT_SIZE]; + int pos = 0; + for (int i = 0; i < cheats_available(); i++) + { + fileTYPE f = {}; + if (cheats[i].enabled) + { + sprintf(filename, "%s/%s", cheat_zip, cheats[i].name); + if (FileOpen(&f, filename)) + { + int len = f.size; + if (!len || (len & 15)) + { + printf("Cheat file %s has incorrect length %d -> skipping.", filename, len); + } + else + { + if (len + pos > CHEAT_SIZE) + { + len = CHEAT_SIZE - pos; + } + + if (FileReadAdv(&f, buff + pos, len) == len) + { + pos += len; + } + else + { + printf("Cannot read cheat file %s.", filename); + } + } + FileClose(&f); + } + else + { + printf("Cannot open cheat file %s.", filename); + } + } + + if (pos >= CHEAT_SIZE) break; + } + + loaded = pos / 16; + printf("Cheat codes: %d\n", loaded); + + user_io_set_index(255); + + // prepare transmission + EnableFpga(); + spi8(UIO_FILE_TX); + spi8(0xff); + DisableFpga(); + + EnableFpga(); + spi8(UIO_FILE_TX_DAT); + spi_write(buff, pos ? pos : 2, fpga_get_fio_size()); + DisableFpga(); + + // signal end of transmission + EnableFpga(); + spi8(UIO_FILE_TX); + spi8(0x00); + DisableFpga(); +} + +void cheats_toggle() +{ + cheats[iSelectedEntry].enabled = !cheats[iSelectedEntry].enabled; + cheats_send(); +} + +int cheats_loaded() +{ + return loaded; +} \ No newline at end of file diff --git a/cheats.h b/cheats.h new file mode 100644 index 0000000..fd9e886 --- /dev/null +++ b/cheats.h @@ -0,0 +1,12 @@ +#ifndef CHEATS_H +#define CHEATS_H + +void cheats_init(char *rom_path); +int cheats_available(); +void cheats_scan(int mode); +void cheats_scroll_name(); +void cheats_print(); +void cheats_toggle(); +int cheats_loaded(); + +#endif diff --git a/file_io.cpp b/file_io.cpp index 5432a1e..cc449d5 100644 --- a/file_io.cpp +++ b/file_io.cpp @@ -33,8 +33,8 @@ typedef std::vector DirentVector; static const size_t YieldIterations = 128; DirentVector DirItem; -int iSelectedEntry = 0; // selected entry index -int iFirstEntry = 0; +static int iSelectedEntry = 0; // selected entry index +static int iFirstEntry = 0; static char full_path[2100]; diff --git a/input.cpp b/input.cpp index efaf3ab..239f31b 100644 --- a/input.cpp +++ b/input.cpp @@ -18,7 +18,7 @@ #include "osd.h" #include "errno.h" -#define NUMDEV 10 +#define NUMDEV 20 #define NUMPLAYERS 6 static int ev2amiga[] = @@ -970,11 +970,22 @@ uint32_t get_key_mod() return modifier & MODMASK; } +enum QUIRK +{ + QUIRK_NONE = 0, + QUIRK_CWIID, + QUIRK_WIIMOTE, + QUIRK_DS3, + QUIRK_DS4, + QUIRK_DS4TOUCH, +}; + typedef struct { uint16_t vid, pid; uint8_t led; - uint8_t axis_state[256]; + uint8_t axis_edge[256]; + int8_t axis_pos[256]; uint8_t num; uint8_t has_map; @@ -988,6 +999,15 @@ typedef struct uint8_t kbdmap[256]; int accx, accy; + int quirk; + + int lightgun_req; + int lightgun; + + int bind; + char devname[32]; + char uniq[32]; + char name[128]; } devInput; static devInput input[NUMDEV] = {}; @@ -1139,26 +1159,34 @@ int toggle_kbdled(int mask) static int mapping = 0; static int mapping_button; -static int mapping_dev; +static int mapping_dev = -1; static int mapping_type; static int mapping_count; static int mapping_clear; +static int mapping_set; static uint32_t tmp_axis[4]; static int tmp_axis_n = 0; -void start_map_setting(int cnt) +void start_map_setting(int cnt, int set) { mapping_button = 0; mapping = 1; - mapping_dev = -1; - mapping_type = (cnt<0) ? 3 : cnt ? 1 : 2; + mapping_set = set; + if (!mapping_set) + { + mapping_dev = -1; + mapping_type = (cnt < 0) ? 3 : cnt ? 1 : 2; + } mapping_count = cnt; mapping_clear = 0; tmp_axis_n = 0; if (mapping_type <= 1 && is_menu_core()) mapping_button = -6; memset(tmp_axis, 0, sizeof(tmp_axis)); + + //un-stick the enter key + user_io_kbd(KEY_ENTER, 0); } int get_map_button() @@ -1209,9 +1237,6 @@ void finish_map_setting(int dismiss) { for (int i = 0; i < NUMDEV; i++) input[i].has_map = 0; - if (mapping_button < 0) mapping_button = 0; - if (!is_menu_core()) for (uint i = mapping_button; i < BTN_NUM; i++) input[mapping_dev].map[i] = 0; - if (!dismiss) FileSaveConfig(get_map_name(mapping_dev, 0), &input[mapping_dev].map, sizeof(input[mapping_dev].map)); if (is_menu_core()) input[mapping_dev].has_mmap = 0; } @@ -1513,11 +1538,15 @@ static void joy_analog(int num, int axis, int offset) } } -static int ds_ver = 0; static int ds_mouse_emu = 0; static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int dev) { + int sub_dev = dev; + + //check if device is a part of multifunctional device + if (input[dev].bind >= 0) dev = input[dev].bind; + //mouse if (ev->type == EV_KEY && ev->code >= BTN_MOUSE && ev->code < BTN_JOYSTICK) { @@ -1545,12 +1574,9 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int } else { - //copy alternative directional buttons, remove system buttons - for (uint i = 0; i < sizeof(input[0].map) / sizeof(input[0].map[0]); i++) + for (uint i = 8; i < sizeof(input[0].map) / sizeof(input[0].map[0]); i++) { - if(i < 4) input[dev].map[i] = (input[dev].map[i] << 16) | (input[dev].map[i + 8] & 0xFFFF); - else if(i < 8) input[dev].map[i] = input[dev].map[i] << 16; - else input[dev].map[i] = 0; + input[dev].map[i] = 0; } } input[dev].has_map++; @@ -1618,16 +1644,17 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int else { int clear = ev->code == KEY_F12 || ev->code == KEY_MENU || ev->code == KEY_HOMEPAGE; - if (mapping_dev < 0 && !clear) + if (ev->value == 1 && mapping_dev < 0 && !clear) { mapping_dev = dev; mapping_type = (ev->code >= 256) ? 1 : 0; + key_mapped = 0; } mapping_clear = 0; if (mapping_dev >= 0 && (mapping_dev == dev || clear) && mapping_button < (is_menu_core() ? 17 : mapping_count)) { - if (ev->value == 1) + if (ev->value == 1 && !key_mapped) { if (is_menu_core()) { @@ -1642,6 +1669,18 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int { input[dev].map[(mapping_button == 16) ? 16 + mapping_type : mapping_button] = ev->code; key_mapped = ev->code; + + //check if analog stick has been used for mouse + if (mapping_button == 9 || mapping_button == 11) + { + if (input[dev].map[mapping_button] >= KEY_EMU && + input[dev].map[mapping_button - 1] >= KEY_EMU && + (input[dev].map[mapping_button - 1] - input[dev].map[mapping_button] == 1) && // same axis + absinfo) + { + input[dev].map[AXIS_MX + (mapping_button - 9)/2] = ((input[dev].map[mapping_button] - KEY_EMU)/2) | 0x20000; + } + } } } } @@ -1659,19 +1698,21 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int { for (uint i = 0; i < sizeof(input[0].map) / sizeof(input[0].map[0]); i++) { - input[dev].map[i] = mapping_type ? input[dev].map[i] << 16 : 0; + input[dev].map[i] &= mapping_set ? 0x0000FFFF : 0xFFFF0000; } } int found = 0; for (int i = 0; i < mapping_button; i++) { - if ((input[dev].map[i] & 0xFFFF) == ev->code) found = 1; + if (mapping_set && (input[dev].map[i] >> 16) == ev->code) found = 1; + if (!mapping_set && (input[dev].map[i] & 0xFFFF) == ev->code) found = 1; } if (!found) { - input[dev].map[mapping_button] = input[dev].map[mapping_button] | (ev->code & 0xFFFF); + if (mapping_set) input[dev].map[mapping_button] = (input[dev].map[mapping_button] & 0xFFFF) | (ev->code << 16); + else input[dev].map[mapping_button] = (input[dev].map[mapping_button] & 0xFFFF0000) | ev->code; key_mapped = ev->code; } } @@ -1798,7 +1839,15 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int { if (ev->value == 1) { - if (idx && mapping_dev >= 0) input[mapping_dev].map[idx] = is_menu_core() ? 0 : (input[mapping_dev].map[idx] & 0xFFFF0000); + if (mapping_dev >= 0) + { + if (idx) input[mapping_dev].map[idx] = 0; + else if (mapping_button > 0) + { + if (is_menu_core()) input[mapping_dev].map[mapping_button] = 0; + else input[mapping_dev].map[mapping_button] &= mapping_set ? 0x0000FFFF : 0xFFFF0000; + } + } mapping_button++; if (mapping_button < 0 && (mapping_button&1)) mapping_button++; } @@ -1842,7 +1891,13 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int if (ev->code == input[dev].mmap[17]) { - if (ev->value <= 1) joy_digital(input[dev].num, 0, 0, ev->value, BTN_OSD); + if (ev->value == 1 && input[dev].lightgun_req && !user_io_osd_is_visible()) + { + input[dev].lightgun = !input[dev].lightgun; + Info(input[dev].lightgun ? "Light Gun mode is ON" : "Light Gun mode is OFF"); + } + else if (ev->value <= 1) joy_digital(input[dev].num, 0, 0, ev->value, BTN_OSD); + return; } @@ -1866,6 +1921,20 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int joy_digital(0, 0, 0, ev->value, BTN_OSD); return; } + + if (input[dev].mmap[AXIS_X]) + { + uint16_t key = KEY_EMU + ((uint16_t)input[dev].mmap[AXIS_X]*2); + if (ev->code == (key + 1)) joy_digital(0, 1 << 0, 0, ev->value, 0); + if (ev->code == key) joy_digital(0, 1 << 1, 0, ev->value, 1); + } + + if (input[dev].mmap[AXIS_Y]) + { + uint16_t key = KEY_EMU + ((uint16_t)input[dev].mmap[AXIS_Y]*2); + if (ev->code == (key + 1)) joy_digital(0, 1 << 2, 0, ev->value, 2); + if (ev->code == key) joy_digital(0, 1 << 3, 0, ev->value, 3); + } } } else @@ -1923,7 +1992,7 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int if (ev->code == input[dev].mmap[15] && (ev->value <= 1) && ((!(mouse_emu & 1)) ^ (!ev->value))) { mouse_emu = ev->value ? mouse_emu | 1 : mouse_emu & ~1; - if (ds_ver == 4) ds_mouse_emu = mouse_emu & 1; + if (input[sub_dev].quirk == QUIRK_DS4) ds_mouse_emu = mouse_emu & 1; printf("mouse_emu = %d\n", mouse_emu); if (mouse_emu & 2) { @@ -2064,15 +2133,45 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int case EV_ABS: if (!user_io_osd_is_visible()) { - // TODO: implement inversion + int hrange = (absinfo->maximum - absinfo->minimum) / 2; + int dead = hrange/63; - //convert to 0..255 range - int value = ((ev->value - absinfo->minimum) * 256) / (absinfo->maximum - absinfo->minimum + 1); - value = (value < 127 || value>129) ? value - 128 : 0; + if (input[sub_dev].quirk == QUIRK_CWIID) + { + if(ev->code == 3 || ev->code == 4) dead = 10; + } + + if (input[sub_dev].quirk == QUIRK_DS3 || input[sub_dev].quirk == QUIRK_DS4) + { + dead = 10; + } + + int value = ev->value; + if (ev->value < absinfo->minimum) value = absinfo->minimum; + else if (ev->value > absinfo->maximum) value = absinfo->maximum; + + // normalize to -range/2...+range/2 + value = value - (absinfo->minimum + absinfo->maximum) / 2; + + if (ev->code > 1 || !input[dev].lightgun) //lightgun has no dead zone + { + // check the dead-zone and remove it from the range + hrange -= dead; + if (value < -dead) value += dead; + else if (value > dead) value -= dead; + else value = 0; + } + + value = (value * 127) / hrange; + + //final check to eliminate additive error if (value < -127) value = -127; - //printf("ABS: axis %d = %d -> %d\n", ev->code, ev->value, value); + else if (value > 127) value = 127; - else if (ev->code == (input[dev].mmap[AXIS_MX] & 0xFFFF) && mouse_emu) + if (input[sub_dev].axis_pos[ev->code & 0xFF] == (int8_t)value) break; + input[sub_dev].axis_pos[ev->code & 0xFF] = (int8_t)value; + + if (ev->code == (input[dev].mmap[AXIS_MX] & 0xFFFF) && mouse_emu) { mouse_emu_x = 0; if (value < -1 || value>1) mouse_emu_x = value; @@ -2086,9 +2185,9 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int mouse_emu_y /= 12; return; } - else if (ev->code == (input[dev].mmap[AXIS_X] & 0xFFFF)) + else if (ev->code == (input[dev].mmap[AXIS_X] & 0xFFFF) || (ev->code == 0 && input[dev].lightgun)) { - // skip if first joystick is not defined. + // skip if joystick is undefined. if (!input[dev].num) break; int offset = 0; @@ -2097,9 +2196,9 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int joy_analog(input[dev].num, 0, offset); return; } - else if (ev->code == (input[dev].mmap[AXIS_Y] & 0xFFFF)) + else if (ev->code == (input[dev].mmap[AXIS_Y] & 0xFFFF) || (ev->code == 1 && input[dev].lightgun)) { - // skip if first joystick is not defined. + // skip if joystick is undefined. if (!input[dev].num) break; int offset = 0; @@ -2114,41 +2213,13 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int } } -static uint16_t read_hex(char *filename) -{ - FILE *in; - unsigned int value; - - in = fopen(filename, "rb"); - if (!in) return 0; - - if (fscanf(in, "%x", &value) == 1) - { - fclose(in); - return (uint16_t)value; - } - fclose(in); - return 0; -} - -static void getVidPid(char *evt, uint16_t *vid, uint16_t *pid) -{ - char name[256]; - sprintf(name, "/sys/class/input/%s/device/id/vendor", evt); - *vid = read_hex(name); - sprintf(name, "/sys/class/input/%s/device/id/product", evt); - *pid = read_hex(name); -} - static struct pollfd pool[NUMDEV + 2]; int input_test(int getchar) { - static char cur_leds = 0; - static int state = 0; + static char cur_leds = 0; + static int state = 0; struct input_absinfo absinfo; - - char devname[32]; struct input_event ev; if (state == 0) @@ -2181,34 +2252,122 @@ int input_test(int getchar) if (state == 1) { printf("Open up to %d input devices.\n", NUMDEV); + for (int i = 0; i < NUMDEV; i++) + { + pool[i].fd = -1; + pool[i].events = 0; + } int n = 0; DIR *d = opendir("/dev/input"); if (d) { + struct input_id id; struct dirent *de; while ((de = readdir(d))) { if (!strncmp(de->d_name, "event", 5)) { - sprintf(devname, "/dev/input/%s", de->d_name); - int fd = open(devname, O_RDWR); + memset(&input[n], 0, sizeof(input[n])); + sprintf(input[n].devname, "/dev/input/%s", de->d_name); + int fd = open(input[n].devname, O_RDWR); + printf("open(%s): %d\n", input[n].devname, fd); + if (fd > 0) { pool[n].fd = fd; pool[n].events = POLLIN; - memset(&input[n], 0, sizeof(input[n])); input[n].led = has_led(pool[n].fd); - getVidPid(de->d_name, &input[n].vid, &input[n].pid); - printf("opened %d: %s (%04x:%04x)\n", n, devname, input[n].vid, input[n].pid); + + memset(&id, 0, sizeof(id)); + ioctl(pool[n].fd, EVIOCGID, &id); + input[n].vid = id.vendor; + input[n].pid = id.product; + + ioctl(pool[n].fd, EVIOCGUNIQ(sizeof(input[n].uniq)), input[n].uniq); + ioctl(pool[n].fd, EVIOCGNAME(sizeof(input[n].name)), input[n].name); + input[n].bind = -1; + if (strcasestr(input[n].name, "Wiimote") && input[n].vid == 1 && input[n].pid == 1) + { + input[n].quirk = QUIRK_CWIID; + input[n].lightgun = 1; + } + + if (input[n].vid == 0x054c) + { + if (input[n].pid == 0x0268) input[n].quirk = QUIRK_DS3; + else if (input[n].pid == 0x05c4 || input[n].pid == 0x09cc) + { + input[n].quirk = QUIRK_DS4; + if (strcasestr(input[n].name, "Touchpad")) + { + input[n].quirk = QUIRK_DS4TOUCH; + } + } + } + + if (input[n].vid == 0x0079 && input[n].pid == 0x1802) + { + strcpy(input[n].uniq, "Mayflash 1802"); + input[n].lightgun = 1; + input[n].num = 2; // force mayflash mode 1/2 as second joystick. + } + + if (input[n].vid == 0x057e && (input[n].pid == 0x0306 || input[n].pid == 0x0330)) + { + if (strcasestr(input[n].name, "Accelerometer")) + { + // don't use Accelerometer + close(pool[n].fd); + continue; + } + else if (strcasestr(input[n].name, "Motion Plus")) + { + // don't use Accelerometer + close(pool[n].fd); + continue; + } + else + { + input[n].quirk = QUIRK_WIIMOTE; + } + } + + // Raphnet devices: clear uniq to prevent merging the ports + if (input[n].vid == 0x289b) + { + memset(input[n].uniq, 0, sizeof(input[n].uniq)); + } + n++; if (n >= NUMDEV) break; } } } closedir(d); - } + // merge multifunctional devices using uniq field + for (int i = 0; i < n; i++) + { + input[i].bind = i; + if (input[i].uniq[0]) + { + for (int j = 0; j < i; j++) + { + if (!memcmp(input[i].uniq, input[j].uniq, sizeof(input[0].uniq))) + { + input[i].bind = j; + break; + } + } + } + } + + for (int i = 0; i < n; i++) + { + printf("opened %d(%2d): %s (%04x:%04x) %d \"%s\" \"%s\"\n", i, input[i].bind, input[i].devname, input[i].vid, input[i].pid, input[i].quirk, input[i].uniq, input[i].name); + } + } cur_leds |= 0x80; state++; } @@ -2225,10 +2384,7 @@ int input_test(int getchar) if ((pool[NUMDEV].revents & POLLIN) && check_devs()) { printf("Close all devices.\n"); - for (int i = 0; i= 0) close(pool[i].fd); - } + for (int i = 0; i= 0) close(pool[i].fd); state = 1; return 0; } @@ -2249,33 +2405,101 @@ int input_test(int getchar) } else if(ev.type) { - ds_ver = 0; - if (input[i].vid == 0x054c) - { - if (input[i].pid == 0x0268) ds_ver = 3; - if (input[i].pid == 0x05c4 || input[i].pid == 0x09cc) ds_ver = 4; - } + int dev = i; + if (input[dev].bind >= 0) dev = input[dev].bind; - if (ds_ver == 4 && ev.type == EV_KEY) + int noabs = 0; + + if (input[i].quirk == QUIRK_DS4TOUCH && ev.type == EV_KEY) { if (ev.code == BTN_TOOL_FINGER || ev.code == BTN_TOUCH || ev.code == BTN_TOOL_DOUBLETAP) continue; } if (ev.type == EV_ABS) { + if (input[i].quirk == QUIRK_WIIMOTE) + { + //nunchuck accel events + if(ev.code >= 3 && ev.code <= 5) continue; + } + //Dualshock: drop accelerator and raw touchpad events - if (ds_ver && ev.code > 40) continue; + if (input[i].quirk == QUIRK_DS4TOUCH && ev.code == 57) + { + input[dev].lightgun_req = (ev.value >= 0); + } + + if ((input[i].quirk == QUIRK_DS4TOUCH || input[i].quirk == QUIRK_DS4 || input[i].quirk == QUIRK_DS3) && ev.code > 40) + { + continue; + } if (ioctl(pool[i].fd, EVIOCGABS(ev.code), &absinfo) < 0) memset(&absinfo, 0, sizeof(absinfo)); else { - //DS4: drop mapped touchpad events. - if (ds_ver == 4 && ev.code <= 1 && absinfo.maximum > 255) continue; + //DS4 specific: touchpad as lightgun + if (input[i].quirk == QUIRK_DS4TOUCH && ev.code <= 1) + { + if (!input[dev].lightgun || user_io_osd_is_visible()) continue; + + if (ev.code == 1) + { + absinfo.minimum = 300; + absinfo.maximum = 850; + } + else if (ev.code == 0) + { + absinfo.minimum = 200; + absinfo.maximum = 1720; + } + else continue; + } + + if (input[i].quirk == QUIRK_DS4 && ev.code <= 1) + { + if (input[dev].lightgun) noabs = 1; + } + + if (input[i].quirk == QUIRK_WIIMOTE) + { + input[dev].lightgun = 0; + if (absinfo.maximum == 1023 || absinfo.maximum == 767) + { + if (user_io_osd_is_visible()) continue; + if (ev.code == 16) + { + ev.value = absinfo.maximum - ev.value; + ev.code = 0; + input[dev].lightgun = 1; + } + else if (ev.code == 17) + { + ev.code = 1; + input[dev].lightgun = 1; + } + // other 3 IR tracking aren't used + else continue; + } + else if (absinfo.maximum == 62) + { + //LT/RT analog + continue; + } + } + } + + if (input[i].quirk == QUIRK_CWIID) + { + if (ev.code == 3 || ev.code == 4) + { + absinfo.minimum = 30; + absinfo.maximum = 225; + } } } //Menu combo on 8BitDo receiver in PSC mode - if (input[i].vid == 0x054c && input[i].pid == 0x0cda && ev.type == EV_KEY) + if (input[dev].vid == 0x054c && input[dev].pid == 0x0cda && ev.type == EV_KEY) { //in PSC mode these keys coming from separate virtual keyboard device //so it's impossible to use joystick codes as keyboards aren't personalized @@ -2284,7 +2508,7 @@ int input_test(int getchar) } //Menu button quirk of 8BitDo gamepad in X-Input mode - if (input[i].vid == 0x045e && input[i].pid == 0x02e0 && ev.type == EV_KEY) + if (input[dev].vid == 0x045e && input[dev].pid == 0x02e0 && ev.type == EV_KEY) { if (ev.code == KEY_MENU) ev.code = BTN_MODE; } @@ -2322,11 +2546,11 @@ int input_test(int getchar) { //keyboard, buttons case EV_KEY: - printf("Input event: type=EV_KEY, code=%d(0x%x), value=%d, jnum=%d, ID:%04x:%04x\n", ev.code, ev.code, ev.value, input[i].num, input[i].vid, input[i].pid); + printf("Input event: type=EV_KEY, code=%d(0x%x), value=%d, jnum=%d, ID:%04x:%04x:%02d\n", ev.code, ev.code, ev.value, input[dev].num, input[dev].vid, input[dev].pid, i); break; case EV_REL: - printf("Input event: type=EV_REL, Axis=%d, Offset=%d, jnum=%d, ID:%04x:%04x\n", ev.code, ev.value, input[i].num, input[i].vid, input[i].pid); + printf("Input event: type=EV_REL, Axis=%d, Offset=%d, jnum=%d, ID:%04x:%04x:%02d\n", ev.code, ev.value, input[dev].num, input[dev].vid, input[dev].pid, i); break; case EV_SYN: @@ -2336,55 +2560,69 @@ int input_test(int getchar) //analog joystick case EV_ABS: //reduce flood from DUALSHOCK 3/4 - if (ds_ver && ev.code <= 5 && ev.value > 118 && ev.value < 138) break; + if ((input[i].quirk == QUIRK_DS4 || input[i].quirk == QUIRK_DS3) && ev.code <= 5 && ev.value > 118 && ev.value < 138) + { + break; + } //aliexpress USB encoder floods messages - if (input[i].vid == 0x0079 && input[i].pid == 0x0006) + if (input[dev].vid == 0x0079 && input[dev].pid == 0x0006) { if (ev.code == 2) break; } - printf("Input event: type=EV_ABS, Axis=%d, Offset=%d, jnum=%d, ID:%04x:%04x.", ev.code, ev.value, input[i].num, input[i].vid, input[i].pid); - printf(" ABS_INFO: min = %d max = %d", absinfo.minimum, absinfo.maximum); - if (absinfo.fuzz) printf(" fuzz = %d", absinfo.fuzz); - if (absinfo.resolution) printf(" res = %d", absinfo.resolution); + printf("Input event: type=EV_ABS, Axis=%d, Offset=%d, jnum=%d, ID:%04x:%04x:%02d,", ev.code, ev.value, input[dev].num, input[dev].vid, input[dev].pid, i); + printf(" abs_min = %d, abs_max = %d", absinfo.minimum, absinfo.maximum); + if (absinfo.fuzz) printf(", fuzz = %d", absinfo.fuzz); + if (absinfo.resolution) printf(", res = %d", absinfo.resolution); printf("\n"); break; default: - printf("Input event: type=%d, code=%d(0x%x), value=%d(0x%x), jnum=%d, ID:%04x:%04x\n", ev.type, ev.code, ev.code, ev.value, ev.value, input[i].num, input[i].vid, input[i].pid); + printf("Input event: type=%d, code=%d(0x%x), value=%d(0x%x), jnum=%d, ID:%04x:%04x:%02d\n", ev.type, ev.code, ev.code, ev.value, ev.value, input[dev].num, input[dev].vid, input[dev].pid, i); } } - input_cb(&ev, &absinfo, i); + if (input[i].quirk == QUIRK_CWIID && ev.type == EV_ABS) + { + if (ev.code <= 1 && user_io_osd_is_visible()) + { + // don't pass IR tracking to OSD + continue; + } + } + + if(!noabs) input_cb(&ev, &absinfo, i); //sumulate digital directions from analog - if (ev.type == EV_ABS && !(mapping && mapping_type<=1 && mapping_button<-4)) + if (ev.type == EV_ABS && !(mapping && mapping_type<=1 && mapping_button<-4) && !(ev.code<=1 && input[dev].lightgun)) { - uint8_t axis_state = 0; + input_absinfo *pai = 0; + uint8_t axis_edge = 0; if ((absinfo.maximum == 1 && absinfo.minimum == -1) || (absinfo.maximum == 2 && absinfo.minimum == 0)) { - if (ev.value == absinfo.minimum) axis_state = 1; - if (ev.value == absinfo.maximum) axis_state = 2; + if (ev.value == absinfo.minimum) axis_edge = 1; + if (ev.value == absinfo.maximum) axis_edge = 2; } else { + pai = &absinfo; int range = absinfo.maximum - absinfo.minimum + 1; int center = absinfo.minimum + (range / 2); int treshold = range / 4; int only_max = 1; - for (int n = 0; n < 4; n++) if (input[i].mmap[AXIS1_X + n] && ((input[i].mmap[AXIS1_X + n] & 0xFFFF) == ev.code)) only_max = 0; + for (int n = 0; n < 4; n++) if (input[dev].mmap[AXIS1_X + n] && ((input[dev].mmap[AXIS1_X + n] & 0xFFFF) == ev.code)) only_max = 0; - if (ev.value < center - treshold && !only_max) axis_state = 1; - if (ev.value > center + treshold) axis_state = 2; + if (ev.value < center - treshold && !only_max) axis_edge = 1; + if (ev.value > center + treshold) axis_edge = 2; } - uint8_t last_state = input[i].axis_state[ev.code & 255]; - input[i].axis_state[ev.code & 255] = axis_state; + uint8_t last_state = input[dev].axis_edge[ev.code & 255]; + input[dev].axis_edge[ev.code & 255] = axis_edge; - //printf("last_state=%d, axis_state=%d\n", last_state, axis_state); - if (last_state != axis_state) + //printf("last_state=%d, axis_edge=%d\n", last_state, axis_edge); + if (last_state != axis_edge) { uint16_t ecode = KEY_EMU + (ev.code << 1) - 1; ev.type = EV_KEY; @@ -2392,23 +2630,23 @@ int input_test(int getchar) { ev.value = 0; ev.code = ecode + last_state; - input_cb(&ev, 0, i); + input_cb(&ev, pai, i); } - if (axis_state) + if (axis_edge) { ev.value = 1; - ev.code = ecode + axis_state; - input_cb(&ev, 0, i); + ev.code = ecode + axis_edge; + input_cb(&ev, pai, i); } } // Menu button on 8BitDo Receiver in D-Input mode - if (ev.code == 9 && input[i].vid == 0x2dc8 && (input[i].pid == 0x3100 || input[i].pid == 0x3104)) + if (ev.code == 9 && input[dev].vid == 0x2dc8 && (input[dev].pid == 0x3100 || input[dev].pid == 0x3104)) { ev.type = EV_KEY; ev.code = KEY_EMU + (ev.code << 1); - input_cb(&ev, &absinfo, i); + input_cb(&ev, pai, i); } } } diff --git a/input.h b/input.h index ea25f30..b835f93 100644 --- a/input.h +++ b/input.h @@ -37,7 +37,7 @@ void input_notify_mode(); int input_poll(int getchar); int is_key_pressed(int key); -void start_map_setting(int cnt); +void start_map_setting(int cnt, int set = 0); int get_map_button(); int get_map_type(); int get_map_clear(); diff --git a/menu.cpp b/menu.cpp index a37b490..76e106f 100644 --- a/menu.cpp +++ b/menu.cpp @@ -48,6 +48,7 @@ along with this program. If not, see . #include "input.h" #include "battery.h" #include "bootcore.h" +#include "cheats.h" #include "support.h" @@ -97,13 +98,21 @@ enum MENU MENU_JOYDIGMAP, MENU_JOYDIGMAP1, MENU_JOYDIGMAP2, + MENU_JOYDIGMAP3, + MENU_JOYDIGMAP4, MENU_JOYKBDMAP, MENU_JOYKBDMAP1, MENU_KBDMAP, MENU_KBDMAP1, + MENU_SCRIPTS_PRE, + MENU_SCRIPTS_PRE1, MENU_SCRIPTS, MENU_SCRIPTS1, MENU_BTPAIR, + MENU_WMPAIR, + MENU_WMPAIR1, + MENU_CHEATS1, + MENU_CHEATS2, // Mist/atari specific pages MENU_MIST_MAIN1, @@ -507,6 +516,35 @@ static int has_bt() return ret; } +static int toggle_wminput() +{ + if (access("/bin/wminput", F_OK) < 0 || access("/media/fat/linux/wiimote.cfg", F_OK) < 0) return -1; + + FILE *fp; + static char out[1035]; + + fp = popen("pidof wminput", "r"); + if (!fp) return -1; + + int ret = -1; + if (fgets(out, sizeof(out) - 1, fp) != NULL) + { + if (strlen(out)) + { + system("killall wminput"); + ret = 0; + } + } + else + { + system("taskset 1 wminput --daemon --config /media/fat/linux/wiimote.cfg &"); + ret = 1; + } + + pclose(fp); + return ret; +} + static char* getNet(int spec) { int netType = 0; @@ -694,6 +732,8 @@ const char* get_rbf_name_bootcore(char *str) return p + 1; } +static int joymap_first = 0; + void HandleUI(void) { switch (user_io_core_type()) @@ -724,6 +764,7 @@ void HandleUI(void) static char drive_num = 0; static char flag; static int cr = 0; + static uint32_t cheatsub = 0; static char cp_MenuCancel; @@ -768,6 +809,13 @@ void HandleUI(void) } break; + case KEY_F10: + if (user_io_osd_is_visible()) + { + //menustate = MENU_WMPAIR; + } + break; + // Within the menu the esc key acts as the menu key. problem: // if the menu is left with a press of ESC, then the follwing // break code for the ESC key when the key is released will @@ -932,42 +980,53 @@ void HandleUI(void) case MENU_ARCHIE_MAIN1: OsdSetTitle(user_io_get_core_name(), OSD_ARROW_RIGHT | OSD_ARROW_LEFT); - menumask = 0xff; - OsdWrite(0, "", 0, 0); + m = 0; + menumask = 0x3ff; + OsdWrite(m++); strcpy(s, " Floppy 0: "); strncat(s, get_image_name(0) ? get_image_name(0) : "* no disk *",27); - OsdWrite(1, s, menusub == 0, 0); + OsdWrite(m++, s, menusub == 0); strcpy(s, " Floppy 1: "); strncat(s, get_image_name(1) ? get_image_name(1) : "* no disk *", 27); - OsdWrite(2, s, menusub == 1, 0); + OsdWrite(m++, s, menusub == 1); - OsdWrite(3, "", 0, 0); + OsdWrite(m++); strcpy(s, " OS ROM: "); strcat(s, archie_get_rom_name()); - OsdWrite(4, s, menusub == 2, 0); + OsdWrite(m++, s, menusub == 2); - OsdWrite(5, "", 0, 0); + OsdWrite(m++); strcpy(s, " Aspect ratio: "); strcat(s, archie_get_ar() ? "16:9" : "4:3"); - OsdWrite(6, s, menusub == 3, 0); + OsdWrite(m++, s, menusub == 3); + + strcpy(s, " Refresh rate: "); + strcat(s, archie_get_60() ? "Variable" : "60Hz"); + OsdWrite(m++, s, menusub == 4); + + OsdWrite(m++); - OsdWrite(7, "", 0, 0); sprintf(s, " Stereo mix: %s", config_stereo_msg[archie_get_amix()]); - OsdWrite(8, s, menusub == 4, 0); + OsdWrite(m++, s, menusub == 5); + + strcpy(s, " 25MHz audio fix: "); + strcat(s, archie_get_afix() ? "Enable" : "Disable"); + OsdWrite(m++, s, menusub == 6); + + OsdWrite(m++); - OsdWrite(9, "", 0, 0); sprintf(s, " Swap joysticks: %s", user_io_get_joyswap() ? "Yes" : "No"); - OsdWrite(10, s, menusub == 5, 0); + OsdWrite(m++, s, menusub == 7); sprintf(s, " Swap mouse btn 2/3: %s", archie_get_mswap() ? "Yes" : "No"); - OsdWrite(11, s, menusub == 6, 0); + OsdWrite(m++, s, menusub == 8); - for (int i = 12; i<15; i++) OsdWrite(i, "", 0, 0); + while(m<15) OsdWrite(m++); - OsdWrite(15, STD_EXIT, menusub == 7, 0); + OsdWrite(15, STD_EXIT, menusub == 9, 0); menustate = MENU_ARCHIE_MAIN2; parentstate = MENU_ARCHIE_MAIN1; @@ -999,21 +1058,31 @@ void HandleUI(void) break; case 4: - archie_set_amix(archie_get_amix()+1); + archie_set_60(!archie_get_60()); menustate = MENU_ARCHIE_MAIN1; break; case 5: - user_io_set_joyswap(!user_io_get_joyswap()); + archie_set_amix(archie_get_amix()+1); menustate = MENU_ARCHIE_MAIN1; break; case 6: + archie_set_afix(!archie_get_afix()); + menustate = MENU_ARCHIE_MAIN1; + break; + + case 7: + user_io_set_joyswap(!user_io_get_joyswap()); + menustate = MENU_ARCHIE_MAIN1; + break; + + case 8: archie_set_mswap(!archie_get_mswap()); menustate = MENU_ARCHIE_MAIN1; break; - case 7: // Exit + case 9: // Exit menustate = MENU_NONE1; break; } @@ -1095,6 +1164,27 @@ void HandleUI(void) selentry++; } + // check for 'C'heats + if (p && (p[0] == 'C')) + { + substrcpy(s, p, 1); + if (strlen(s)) + { + strcpy(s, " "); + substrcpy(s + 1, p, 1); + } + else + { + strcpy(s, " Cheats"); + } + MenuWrite(entry, s, menusub == selentry, !cheats_available()); + + // add bit in menu mask + menumask = (menumask << 1) | 1; + entry++; + selentry++; + } + // check for 'T'oggle and 'R'eset (toggle and then close menu) strings if (p && ((p[0] == 'T') || (p[0] == 'R'))) { @@ -1241,7 +1331,13 @@ void HandleUI(void) entry++; } - if (p[0] == 'F') + if (p[0] == 'C' && cheats_available()) + { + menustate = MENU_CHEATS1; + cheatsub = menusub; + menusub = 0; + } + else if (p[0] == 'F') { opensave = (p[1] == 'S'); substrcpy(ext, p, 1); @@ -1298,7 +1394,6 @@ void HandleUI(void) menustate = MENU_8BIT_MAIN1; if (p[0] == 'R') menustate = MENU_NONE1; } - } } } @@ -1317,6 +1412,7 @@ void HandleUI(void) case MENU_8BIT_MAIN_FILE_SELECTED: printf("File selected: %s\n", SelectedPath); user_io_file_tx(SelectedPath, user_io_ext_idx(SelectedPath, fs_pFileExt) << 6 | (menusub + 1), opensave); + cheats_init(SelectedPath); menustate = MENU_NONE1; break; @@ -1445,6 +1541,7 @@ void HandleUI(void) start_map_setting(joy_bcount ? joy_bcount+4 : 8); menustate = MENU_JOYDIGMAP; menusub = 0; + joymap_first = 1; break; case 2: @@ -1750,7 +1847,7 @@ void HandleUI(void) case MENU_JOYDIGMAP: helptext = 0; - menumask = 0; + menumask = 1; OsdSetTitle("Define buttons", 0); menustate = MENU_JOYDIGMAP1; parentstate = MENU_JOYDIGMAP; @@ -1758,11 +1855,6 @@ void HandleUI(void) OsdWrite(7, " Esc \x16 Cancel"); OsdWrite(8, " Enter \x16 Finish"); OsdWrite(9, " Space \x16 Skip"); - if (!is_menu_core()) - { - OsdWrite(13, " You may define 2 sets of"); - OsdWrite(14, " buttons on the same gamepad"); - } break; case MENU_JOYDIGMAP1: @@ -1772,6 +1864,7 @@ void HandleUI(void) OsdWrite(3); OsdWrite(4, " Clearing"); OsdWrite(5); + joymap_first = 1; break; } @@ -1789,7 +1882,7 @@ void HandleUI(void) p = joy_bnames[get_map_button() - 4]; if (is_menu_core()) { - if (get_map_type()) joy_bcount = 17; + if (get_map_type()) joy_bcount = 15; if (get_map_button() == 16) p = joy_button_map[8 + get_map_type()]; } } @@ -1844,7 +1937,13 @@ void HandleUI(void) } } - if (select || menu || get_map_button() >= (joy_bcount ? joy_bcount + 4 : 8)) + if (!is_menu_core() && (get_map_button() >= (joy_bcount ? joy_bcount + 4 : 8) || (select & get_map_vid() & get_map_pid())) && joymap_first && get_map_type()) + { + finish_map_setting(0); + menustate = MENU_JOYDIGMAP3; + menusub = 0; + } + else if (select || menu || get_map_button() >= (joy_bcount ? joy_bcount + 4 : 8)) { finish_map_setting(menu); if (is_menu_core()) @@ -1869,6 +1968,44 @@ void HandleUI(void) } break; + case MENU_JOYDIGMAP3: + for (int i = 0; i < OsdGetSize(); i++) OsdWrite(i); + m = 6; + menumask = 3; + OsdWrite(m++, " Do you want to setup"); + OsdWrite(m++, " alternative buttons?"); + OsdWrite(m++, " No", menusub == 0); + OsdWrite(m++, " Yes", menusub == 1); + parentstate = menustate; + menustate = MENU_JOYDIGMAP4; + break; + + case MENU_JOYDIGMAP4: + if (menu) + { + menustate = MENU_8BIT_SYSTEM1; + menusub = 1; + break; + } + else if (select) + { + switch (menusub) + { + case 0: + menustate = MENU_8BIT_SYSTEM1; + menusub = 1; + break; + + case 1: + start_map_setting(joy_bcount ? joy_bcount + 4 : 8, 1); + menustate = MENU_JOYDIGMAP; + menusub = 0; + joymap_first = 0; + break; + } + } + break; + case MENU_JOYKBDMAP: helptext = 0; menumask = 1; @@ -1947,7 +2084,7 @@ void HandleUI(void) OsdDrawLogo(3); OsdDrawLogo(4); - sprintf(s, " HPS s/w v%s", version + 5); + sprintf(s, " MiSTer v%s", version + 5); OsdWrite(10, s, 0, 0, 1); s[0] = 0; @@ -2794,6 +2931,73 @@ void HandleUI(void) break; + /******************************************************************/ + /* cheats menu */ + /******************************************************************/ + case MENU_CHEATS1: + helptext = helptexts[HELPTEXT_NONE]; + sprintf(s, "Cheats (%d)", cheats_loaded()); + OsdSetTitle(s); + cheats_print(); + menustate = MENU_CHEATS2; + parentstate = menustate; + break; + + case MENU_CHEATS2: + menumask = 0; + + if (menu) + { + menustate = MENU_8BIT_MAIN1; + menusub = cheatsub; + break; + } + + cheats_scroll_name(); + + if (c == KEY_HOME) + { + cheats_scan(SCANF_INIT); + menustate = MENU_CHEATS1; + } + + if (c == KEY_END) + { + cheats_scan(SCANF_END); + menustate = MENU_CHEATS1; + } + + if ((c == KEY_PAGEUP) || (c == KEY_LEFT)) + { + cheats_scan(SCANF_PREV_PAGE); + menustate = MENU_CHEATS1; + } + + if ((c == KEY_PAGEDOWN) || (c == KEY_RIGHT)) + { + cheats_scan(SCANF_NEXT_PAGE); + menustate = MENU_CHEATS1; + } + + if (down) // scroll down one entry + { + cheats_scan(SCANF_NEXT); + menustate = MENU_CHEATS1; + } + + if (up) // scroll up one entry + { + cheats_scan(SCANF_PREV); + menustate = MENU_CHEATS1; + } + + if (select) + { + cheats_toggle(); + menustate = MENU_CHEATS1; + } + break; + /******************************************************************/ /* reset menu */ /******************************************************************/ @@ -3421,7 +3625,17 @@ void HandleUI(void) OsdSetTitle("System Settings", 0); OsdWrite(0, "", 0, 0); - sprintf(s, " HPS s/w v%s", version + 5); + sprintf(s, " MiSTer v%s", version + 5); + { + char str[8] = {}; + FILE *f = fopen("/MiSTer.version", "r"); + if (f) + { + if (fread(str, 6, 1, f)) sprintf(s, " MiSTer v%s, OS v%s", version + 5, str); + fclose(f); + } + } + OsdWrite(1, s, 0, 0); { @@ -3497,26 +3711,90 @@ void HandleUI(void) strcpy(joy_bnames[1], "Btn 2 (ESC/Back)"); strcpy(joy_bnames[2], "Btn 3 (Backspace)"); strcpy(joy_bnames[3], "Btn 4"); - strcpy(joy_bnames[4], "RIGHT (Alt/Mouse)"); - strcpy(joy_bnames[5], "LEFT (Alt/Mouse)"); - strcpy(joy_bnames[6], "DOWN (Alt/Mouse)"); - strcpy(joy_bnames[7], "UP (Alt/Mouse)"); + strcpy(joy_bnames[4], "Mouse Move RIGHT"); + strcpy(joy_bnames[5], "Mouse Move LEFT"); + strcpy(joy_bnames[6], "Mouse Move DOWN"); + strcpy(joy_bnames[7], "Mouse Move UP"); strcpy(joy_bnames[8], "Mouse Left Btn"); strcpy(joy_bnames[9], "Mouse Right Btn"); strcpy(joy_bnames[10], "Mouse Middle Btn"); strcpy(joy_bnames[11], "Mouse Emu/Sniper"); - start_map_setting(21); + start_map_setting(19); menustate = MENU_JOYDIGMAP; menusub = 0; break; case 3: - SelectFile("SH", SCANO_DIR, MENU_SCRIPTS, MENU_FIRMWARE1); + menustate = MENU_SCRIPTS_PRE; + menusub = 0; break; } } printSysInfo(); break; + case MENU_WMPAIR: + { + OsdSetTitle("Wiimote", 0); + int res = toggle_wminput(); + menu_timer = GetTimer(2000); + for (int i = 0; i < OsdGetSize(); i++) OsdWrite(i); + if (res < 0) OsdWrite(7, " Cannot enable Wiimote"); + else if (res == 0) OsdWrite(7, " Wiimote disabled"); + else + { + OsdWrite(7, " Wiimote enabled"); + OsdWrite(9, " Press 1+2 to connect"); + menu_timer = GetTimer(3000); + } + menustate = MENU_WMPAIR1; + } + //fall through + + case MENU_WMPAIR1: + if (CheckTimer(menu_timer)) menustate = MENU_NONE1; + break; + + case MENU_SCRIPTS_PRE: + OsdSetTitle("Warning!!!", 0); + helptext = 0; + menumask = 3; + m = 0; + OsdWrite(m++); + OsdWrite(m++, " Attention:"); + OsdWrite(m++, " This is dangerous operation!"); + OsdWrite(m++); + OsdWrite(m++, " Script has control over the"); + OsdWrite(m++, " whole system and may damage"); + OsdWrite(m++, " the files or settings, then"); + OsdWrite(m++, " MiSTer won't boot, so you"); + OsdWrite(m++, " will have to re-format the"); + OsdWrite(m++, " SD card and fill with files"); + OsdWrite(m++, " in order to use it again."); + OsdWrite(m++); + OsdWrite(m++); + OsdWrite(m++, " Do you want to continue?"); + OsdWrite(m++, " No", menusub == 0); + OsdWrite(m++, " Yes", menusub == 1); + menustate = MENU_SCRIPTS_PRE1; + parentstate = MENU_SCRIPTS_PRE; + break; + + case MENU_SCRIPTS_PRE1: + if (menu) menustate = MENU_FIRMWARE1; + else if (select) + { + switch (menusub) + { + case 0: + menustate = MENU_FIRMWARE1; + break; + case 1: + SelectFile("SH", SCANO_DIR, MENU_SCRIPTS, MENU_FIRMWARE1); + break; + } + } + break; + case MENU_BTPAIR: OsdSetSize(16); OsdEnable(DISABLE_KEYBOARD); @@ -3750,6 +4028,7 @@ void open_joystick_setup() OsdEnable(DISABLE_KEYBOARD); start_map_setting(joy_bcount ? joy_bcount + 4 : 8); menustate = MENU_JOYDIGMAP; + joymap_first = 1; } void ScrollLongName(void) @@ -3786,7 +4065,7 @@ void ScrollLongName(void) if (flist_SelectedItem()->d_type == DT_DIR) max_len = 25; // number of directory name characters to display - ScrollText(flist_iSelectedEntry()-flist_iFirstEntry(), flist_SelectedItem()->d_name, 2, len, max_len, 1); + ScrollText(flist_iSelectedEntry()-flist_iFirstEntry(), flist_SelectedItem()->d_name, 0, len, max_len, 1); } void PrintFileName(char *name, int row, int maxinv) diff --git a/osd.cpp b/osd.cpp index 89dc669..e67f7ee 100644 --- a/osd.cpp +++ b/osd.cpp @@ -397,7 +397,7 @@ void OsdDrawLogo(int row) } // write a null-terminated string to the OSD buffer starting at line -void OSD_PrintText(unsigned char line, const char *text, unsigned long start, unsigned long width, unsigned long offset, unsigned char invert) +void OSD_PrintText(unsigned char line, const char *hdr, const char *text, unsigned long start, unsigned long width, unsigned long offset, unsigned char invert) { // line : OSD line number (0-7) // text : pointer to null-terminated string @@ -419,45 +419,53 @@ void OSD_PrintText(unsigned char line, const char *text, unsigned long start, un invert = 0xff; p = &titlebuffer[(osd_size - 1 - line) * 8]; - if (start>2) { + if (start>2) + { spi16(0xffff); start -= 2; } i = start>16 ? 16 : start; - for (j = 0; j<(i / 2); ++j) - spi_n(255 ^ *p++, 2); + for (j = 0; j<(i / 2); ++j) spi_n(255 ^ *p++, 2); - if (i & 1) - spi8(255 ^ *p); + if (i & 1) spi8(255 ^ *p); start -= i; - if (start>2) { + if (start>2) + { spi16(0xffff); start -= 2; } - while (start--) - spi8(0x00); + while (start--) spi8(0x00); - if (offset) { + while(*hdr) + { + width -= 8; + p = charfont[(uint)(*hdr++)]; + for (int i=0; i < 8; i++) spi8(*p++^invert); + } + + if (offset) + { width -= 8 - offset; p = &charfont[(uint)(*text++)][offset]; for (; offset < 8; offset++) spi8(*p++^invert); } - while (width > 8) { + while (width > 8) + { unsigned char b; p = &charfont[(uint)(*text++)][0]; for (b = 0; b<8; b++) spi8(*p++^invert); width -= 8; } - if (width) { + if (width) + { p = &charfont[(uint)(*text++)][0]; - while (width--) - spi8(*p++^invert); + while (width--) spi8(*p++^invert); } DisableOsd(); @@ -640,12 +648,21 @@ void ScrollText(char n, const char *str, int off, int len, int max_len, unsigned #define BLANKSPACE 10 // number of spaces between the end and start of repeated name - char s[40]; + char s[40], hdr[40]; long offset; if (!max_len) max_len = 30; if (str && str[0] && CheckTimer(scroll_timer)) // scroll if long name and timer delay elapsed { + hdr[0] = 0; + if (off) + { + strncpy(hdr, str, off); + hdr[off] = 0; + str += off; + if (len > off) len -= off; + } + scroll_timer = GetTimer(SCROLL_DELAY2); // reset scroll timer to repeat delay scroll_offset++; // increase scroll position (1 pixel unit) @@ -653,7 +670,7 @@ void ScrollText(char n, const char *str, int off, int len, int max_len, unsigned if (!len) len = strlen(str); // get name length - if (off+len > max_len) // scroll name if longer than display size + if (off+2+len > max_len) // scroll name if longer than display size { // reset scroll position if it exceeds predefined maximum if (scroll_offset >= (uint)(len + BLANKSPACE) << 3) scroll_offset = 0; @@ -668,7 +685,7 @@ void ScrollText(char n, const char *str, int off, int len, int max_len, unsigned strncpy(s + len + BLANKSPACE, str, max_len - len - BLANKSPACE); // repeat the name after its end and predefined number of blank space } - OSD_PrintText(n, s, 22, (max_len - 1) << 3, (scroll_offset & 0x7), invert); // OSD print function with pixel precision + OSD_PrintText(n, hdr, s, 22, (max_len - 1) << 3, (scroll_offset & 0x7), invert); // OSD print function with pixel precision } } } diff --git a/releases/MiSTer_20190427 b/releases/MiSTer_20190427 new file mode 100644 index 0000000..83918c3 Binary files /dev/null and b/releases/MiSTer_20190427 differ diff --git a/releases/MiSTer_20190501 b/releases/MiSTer_20190501 new file mode 100644 index 0000000..11a3feb Binary files /dev/null and b/releases/MiSTer_20190501 differ diff --git a/support/archie/archie.cpp b/support/archie/archie.cpp index 766c2ab..35511d6 100644 --- a/support/archie/archie.cpp +++ b/support/archie/archie.cpp @@ -84,17 +84,41 @@ int archie_get_ar() return config.system_ctrl & 1; } -static int mswap = 0; -void archie_set_mswap(char i) -{ - mswap = i; -} - -int archie_get_mswap() -{ - return mswap; -} - +void archie_set_60(char i) +{ + if (i) config.system_ctrl |= 0b1000; + else config.system_ctrl &= ~0b1000; + user_io_8bit_set_status((i ? -1 : 0), 0b10000); +} + +int archie_get_60() +{ + return config.system_ctrl & 0b1000; +} + +void archie_set_afix(char i) +{ + if (i) config.system_ctrl |= 0b10000; + else config.system_ctrl &= ~0b10000; + user_io_8bit_set_status((i ? -1 : 0), 0b100000); +} + +int archie_get_afix() +{ + return config.system_ctrl & 0b10000; +} + +static int mswap = 0; +void archie_set_mswap(char i) +{ + mswap = i; +} + +int archie_get_mswap() +{ + return mswap; +} + void archie_set_amix(char i) { config.system_ctrl = (config.system_ctrl & ~0b110) | ((i & 3)<<1); @@ -190,6 +214,9 @@ void archie_init(void) archie_set_ar(archie_get_ar()); archie_set_amix(archie_get_amix()); + archie_set_60(archie_get_60()); + archie_set_afix(archie_get_afix()); + // upload rom file archie_set_rom(config.rom_img); @@ -381,27 +408,27 @@ void archie_poll(void) // arm acks first byte case BACK: - if (kbd_state != STATE_WAIT4ACK1) { - archie_debugf("KBD unexpected BACK, resetting KBD"); - kbd_state = STATE_HRST; - } - else { -#ifdef HOLD_OFF_TIME - // wait some time before sending next byte - archie_debugf("KBD starting hold off"); - kbd_state = STATE_HOLD_OFF; - hold_off_timer = GetTimer(10); - // wait some time before sending next byte - archie_debugf("KBD starting hold off"); - kbd_state = STATE_HOLD_OFF; - hold_off_timer = GetTimer(10); -#else - kbd_state = STATE_IDLE; - archie_check_queue(); - kbd_state = STATE_IDLE; - archie_check_queue(); -#endif - } + if (kbd_state != STATE_WAIT4ACK1) { + archie_debugf("KBD unexpected BACK, resetting KBD"); + kbd_state = STATE_HRST; + } + else { +#ifdef HOLD_OFF_TIME + // wait some time before sending next byte + archie_debugf("KBD starting hold off"); + kbd_state = STATE_HOLD_OFF; + hold_off_timer = GetTimer(10); + // wait some time before sending next byte + archie_debugf("KBD starting hold off"); + kbd_state = STATE_HOLD_OFF; + hold_off_timer = GetTimer(10); +#else + kbd_state = STATE_IDLE; + archie_check_queue(); + kbd_state = STATE_IDLE; + archie_check_queue(); +#endif + } break; // arm acks second byte diff --git a/support/archie/archie.h b/support/archie/archie.h index 4f0b3a5..0b7b1e2 100644 --- a/support/archie/archie.h +++ b/support/archie/archie.h @@ -15,7 +15,11 @@ void archie_set_ar(char i); int archie_get_ar(); void archie_set_amix(char i); int archie_get_amix(); -void archie_set_mswap(char i); -int archie_get_mswap(); +void archie_set_mswap(char i); +int archie_get_mswap(); +void archie_set_60(char i); +int archie_get_60(); +void archie_set_afix(char i); +int archie_get_afix(); #endif // ARCHIE_H diff --git a/user_io.h b/user_io.h index 4264fb4..8af8718 100644 --- a/user_io.h +++ b/user_io.h @@ -241,7 +241,7 @@ void user_io_set_scaler_coeff(char *name); void user_io_minimig_set_adjust(char n); char user_io_minimig_get_adjust(); -#define HomeDir (is_minimig() ? "Amiga" : is_archie() ? "Archie" : user_io_get_core_name()) +#define HomeDir (is_minimig() ? "Amiga" : is_archie() ? "Archie" : is_menu_core() ? "Scripts" : user_io_get_core_name()) int GetUARTMode(); int GetMidiLinkMode();