From 383ce78c91b5c712da1dce5009bd1058dd3817f6 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 2 Feb 2015 16:01:49 -0800 Subject: [PATCH] VAX,MicroVAX,QVSS: Video improvements VIDEO: - Make mouse motion activity consistent with SDL relative direction. Add error output when mouse events are discarded due to queue full. If a client application delivers motion information in a different relative sense, then that application needs to make the adjustments from the SDL standard direction. - Added SHOW dev VIDEO capability to describe the underlying SDL video capabilities of the current SDL library and host execution environment. - Force software based rendering under SDL2. Enhanced debug info. - Added host OS cursor integration support. - Reorganize libSDL vs libSDL2 version implementation to leverage common logic without replication. QVSS: - Coalesced adjacent screen row updates to minimize vid_draw operations - Report all relative mouse motion in the mouse position register AND mouse motion data. - Added debugging information for cursor and scan line map updates - Add option "SET QVSS CAPTURED" to force capture input mode. --- VAX/vax_vc.c | 241 ++++++-- VAX/vax_vs.c | 24 +- sim_video.c | 1537 +++++++++++++++++++++++--------------------------- sim_video.h | 18 +- 4 files changed, 950 insertions(+), 870 deletions(-) diff --git a/VAX/vax_vc.c b/VAX/vax_vc.c index aad42884..4f73d6ea 100644 --- a/VAX/vax_vc.c +++ b/VAX/vax_vc.c @@ -40,17 +40,17 @@ /* CSR - control/status register */ BITFIELD vc_csr_bits[] = { - BIT(MOD), /* Monitor size */ -#define CSR_V_MDO 0 -#define CSR_MOD (1< VR260(19"), 0 -> (15") */ +#define CSR_V_MOD 0 +#define CSR_MOD (1<AND, 1->OR) */ #define VSYNC_TIME 8000 /* vertical sync interval */ @@ -217,15 +217,18 @@ uint32 vc_csr = 0; /* Control/status */ uint32 vc_curx = 0; /* Cursor X-position */ uint32 vc_cur_x = 0; /* Last cursor X-position */ uint32 vc_cur_y = 0; /* Last cursor Y-position */ -uint32 vc_cur_f = 0; /* Last cursor function */ +uint32 vc_cur_f = 0; /* Last cursor function (0->AND, 1->OR) */ t_bool vc_cur_v = FALSE; /* Last cursor visible */ +t_bool vc_cur_new_data = FALSE; /* New Cursor image data */ +t_bool vc_input_captured = FALSE; /* Mouse and Keyboard input captured in video window */ uint32 vc_mpos = 0; /* Mouse position */ uint32 vc_crtc[CRTC_SIZE]; /* CRTC registers */ uint32 vc_crtc_p = 0; /* CRTC pointer */ uint32 vc_icdr = 0; /* Interrupt controller data */ uint32 vc_icsr = 0; /* Interrupt controller status */ -uint32 vc_map[1024]; /* Scanline map */ +uint32 *vc_map; /* Scanline map */ uint32 *vc_buf = NULL; /* Video memory */ +uint32 *vc_lines = NULL; /* Video Display Lines */ uint8 vc_cur[256]; /* Cursor image */ DEVICE vc_dev; @@ -234,6 +237,8 @@ t_stat vc_wr (int32 data, int32 PA, int32 access); t_stat vc_svc (UNIT *uptr); t_stat vc_reset (DEVICE *dptr); t_stat vc_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat vc_set_capture (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat vc_show_capture (FILE* st, UNIT* uptr, int32 val, void* desc); void vc_setint (int32 src); int32 vc_inta (void); void vc_clrint (int32 src); @@ -255,9 +260,12 @@ DIB vc_dib = { 2, IVCL (QVSS), VEC_AUTO, { &vc_inta, &vc_inta } }; -/* Debugging Bisim_tmaps */ +/* Debugging Bitmaps */ #define DBG_REG 0x0100 /* register activity */ +#define DBG_CRTC 0x0200 /* crtc register activity */ +#define DBG_CURSOR 0x0400 /* Cursor content, function and visibility activity */ +#define DBG_SCANL 0x0800 /* Scanline map activity */ #define DBG_INT0 0x0001 /* interrupt 0 */ #define DBG_INT1 0x0002 /* interrupt 1 */ #define DBG_INT2 0x0004 /* interrupt 2 */ @@ -270,6 +278,9 @@ DIB vc_dib = { DEBTAB vc_debug[] = { {"REG", DBG_REG}, + {"CRTC", DBG_CRTC}, + {"CURSOR", DBG_CURSOR}, + {"SCANL", DBG_SCANL}, {"DUART", DBG_INT0}, {"VSYNC", DBG_INT1}, {"MOUSE", DBG_INT2}, @@ -280,6 +291,7 @@ DEBTAB vc_debug[] = { {"SPARE", DBG_INT7}, {"INT", DBG_INT0|DBG_INT1|DBG_INT2|DBG_INT3|DBG_INT4|DBG_INT5|DBG_INT6|DBG_INT7}, {"VMOUSE", SIM_VID_DBG_MOUSE}, + {"VCURSOR", SIM_VID_DBG_CURSOR}, {"VKEY", SIM_VID_DBG_KEY}, {"VVIDEO", SIM_VID_DBG_VIDEO}, {0} @@ -302,7 +314,6 @@ REG vc_reg[] = { { BRDATA (VEC, vc_intc.vec, 16, 32, 8) }, { BRDATAD (CRTC, vc_crtc, 16, 8, CRTC_SIZE, "CRTC registers") }, { HRDATAD (CRTCP, vc_crtc_p, 8, "CRTC pointer") }, - { BRDATAD (MAP, vc_map, 16, 16, 1024, "Scanline map") }, { NULL } }; @@ -311,8 +322,14 @@ MTAB vc_mod[] = { &vc_set_enable, NULL, NULL, "Enable VCB01 (QVSS)" }, { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLE", &vc_set_enable, NULL, NULL, "Disable VCB01 (QVSS)" }, - { MTAB_XTD|MTAB_VDV, 0, "RELEASEKEY", NULL, - NULL, &vid_show_release_key, NULL, "Display the window focus release key" }, + { MTAB_XTD|MTAB_VDV, TRUE, NULL, "CAPTURE", + &vc_set_capture, &vc_show_capture, NULL, "Enable Captured Input Mode" }, + { MTAB_XTD|MTAB_VDV, FALSE, NULL, "NOCAPTURE", + &vc_set_capture, NULL, NULL, "Disable Captured Input Mode" }, + { MTAB_XTD|MTAB_VDV, TRUE, "OSCURSOR", NULL, + NULL, &vc_show_capture, NULL, "Display Input Capture mode" }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "VIDEO", NULL, + NULL, &vid_show_video, NULL, "Display the host system video capabilities" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 004, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL, "Bus address" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR", @@ -371,6 +388,30 @@ char *vc_regnames[] = { "", /* +62 spare */ }; +char *vc_crtc_regnames[] = { + "HTOT", /* Horizontal Total The total number of character times in a line, minus 1 */ + "HDSP", /* Horizontal Displayed The total number of displayed characters in a line. */ + "HPOS", /* HSYNC Position Defines the number of character times until HSYNC (horizontal sync). */ + "HVWD", /* HSYNC/VSYNC Widths Four bits each are used to define the HSYNC + pulse width and the VSYNC (vertical sync) pulse width. */ + "VTOT", /* Vertical Total Total number of character rows on the screen, minus 1. */ + "VTOA", /* Vertical Total Adjust The number of scan lines to complete the screen. */ + "VDSP", /* Vertical Displayed The number of character rows displayed. */ + "VPOS", /* VSYNC Position The number of character rows until VSYNC. */ + "MODE", /* Mode Controls addressing, interlace, and cursor. */ + "MSCN", /* Maximum Scan Line The number of scan lines in a character row, minus 1. */ + "CSCS", /* Cursor Scan Start Defines the scan line at which the cursor starts. */ + "CSCE", /* Cursor Scan End Defines where the cursor ends. */ + "SAH", /* Start Address High Defines the RAM location where video refresh */ + "SAL", /* Start Address Low begins. */ + "CAH", /* Cursor Address High Defines the cursor position in RAM. */ + "CAL", /* Cursor Address Low */ + "LPPL", /* Light Pen Position High Contains the position of the light pen. */ + "LPPH", /* Light Pen Position Low */ + "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31" +}; + + t_stat vc_rd (int32 *data, int32 PA, int32 access) { uint32 rg = (PA >> 1) & 0x1F; @@ -393,6 +434,7 @@ switch (rg) { case 4: /* CRTC addr ptr */ *data = vc_crtc_p; + sim_debug (DBG_CRTC, &vc_dev, "CRTC-Addr Read: %d - %s\n", vc_crtc_p, vc_crtc_regnames[vc_crtc_p & CRTCP_REG]); break; case 5: /* CRTC data */ @@ -400,6 +442,7 @@ switch (rg) { *data = vc_crtc[crtc_rg]; if ((crtc_rg == CRTC_LPPL) || (crtc_rg == CRTC_LPPH)) vc_crtc_p &= ~CRTCP_LPF; /* Clear light pen full */ + sim_debug (DBG_CRTC, &vc_dev, "CRTC-Data:%s[%d] Read: 0x%x\n", vc_crtc_regnames[crtc_rg], crtc_rg, *data); break; case 6: /* ICDR */ @@ -461,6 +504,7 @@ t_stat vc_wr (int32 data, int32 PA, int32 access) { uint32 rg = (PA >> 1) & 0x1F; uint32 crtc_rg; +uint32 old_data; sim_debug (DBG_REG, &vc_dev, "vc_wr(%s) data=0x%04X\n", vc_regnames[(PA >> 1) & 0x1F], data); switch (rg) { @@ -470,11 +514,17 @@ switch (rg) { sim_cancel (&vc_unit); /* reactivate with short delay */ sim_activate (&vc_unit, VSYNC_TIME); /* in case software checks for vsync */ } + old_data = vc_csr; vc_csr = (vc_csr & ~CSR_RW) | (data & CSR_RW); + if ((vc_csr ^ old_data) & CSR_FNC) { + sim_debug (DBG_CURSOR, &vc_dev, "Cursor Function changed to: %s\n", CUR_F ? "OR" : "AND"); + } break; case 1: /* Cursor X */ vc_curx = data; + sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "Cursor-X set: %d\n", vc_curx); + vid_set_cursor_position (CUR_X, CUR_Y); break; case 2: /* Mouse position */ @@ -482,11 +532,30 @@ switch (rg) { case 4: /* CRTC addr ptr */ vc_crtc_p = (vc_crtc_p & ~CRTCP_RW) | (data & CRTCP_RW); + sim_debug (DBG_CRTC, &vc_dev, "CRTC-Addr Set: %d - %s\n", vc_crtc_p, vc_crtc_regnames[vc_crtc_p & CRTCP_REG]); break; case 5: /* CRTC data */ crtc_rg = vc_crtc_p & CRTCP_REG; + old_data = vc_crtc[crtc_rg]; vc_crtc[crtc_rg] = data & BMASK; + sim_debug (DBG_CRTC, &vc_dev, "CRTC-Data:%s[%d] Set: 0x%x\n", vc_crtc_regnames[crtc_rg], crtc_rg, vc_crtc[crtc_rg]); + if (crtc_rg == CRTC_CAH) { + sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "Cursor-Y-High set (%d). Y value: %d\n", vc_crtc[crtc_rg], CUR_Y); + vid_set_cursor_position (CUR_X, CUR_Y); + } + if (crtc_rg == CRTC_CAL) { + sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "Cursor-Y-Low set (%d). Y value: %d\n", vc_crtc[crtc_rg], CUR_Y); + } + if (crtc_rg == CRTC_MSCN) { + sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "Maximum Scan Line set (%d). Y value: %d\n", vc_crtc[crtc_rg], CUR_Y); + } + if (crtc_rg == CRTC_CSCS) { + if (0x20 & (old_data ^ vc_crtc[crtc_rg])) { + sim_debug (DBG_CURSOR, &vc_dev, "Visibility Changed to: %s\n", CUR_V ? "Visible" : "Invisible"); + } + sim_debug (SIM_VID_DBG_MOUSE, &vc_dev, "CSCS set (%d). Y value: %d\n", vc_crtc[crtc_rg], CUR_Y); + } break; case 6: /* ICDR */ @@ -622,8 +691,18 @@ else nval = (uint32)val; if (rg >= 0xFFF8) { /* cursor image */ idx = (pa << 3) & 0xFF; /* get byte index */ + if (sim_deb) { + char binary[40]; + int32 i; + + for (i=0; i<8*lnt; i++) + binary[i] = '0' + ((val & (1 << i)) != 0); + binary[i] = '\0'; + sim_debug (DBG_CURSOR, &vc_dev, "Cursor Data at 0x%X set to 0x%0*X - %s\n", rg, 2*lnt, val, binary); + } for (i = 0; i < (lnt << 3); i++) vc_cur[idx++] = (val >> i) & 1; /* 1bpp to 8bpp */ + vc_cur_new_data = TRUE; } else if (rg >= 0xFE00) { /* scanline map */ if (vc_buf[rg] != nval) { @@ -631,6 +710,7 @@ else if (rg >= 0xFE00) { /* scanline map */ sc = (scrln & 1) ? 16 : 0; /* odd line? (upper word) */ bufln = (nval >> sc) & 0x7FF; /* buffer line */ vc_map[scrln] = bufln; /* update map */ + sim_debug (DBG_SCANL, &vc_dev, "Scan Line 0x%X set to 0x%X\n", scrln, bufln); if (lnt > L_WORD) { /* remapping 2 lines? */ scrln++; /* next screen line */ @@ -642,7 +722,7 @@ else if (rg >= 0xFE00) { /* scanline map */ bufln = rg / 32; for (scrln = 0; scrln < 1024; scrln++) { if ((vc_map[scrln] & 0x7FF) == bufln) { - vc_map[scrln] = vc_map[scrln] & ~VCMAP_VLD; /* invalidate map */ + vc_map[scrln] &= ~VCMAP_VLD; /* invalidate map */ } } vc_buf[rg] = nval; @@ -651,8 +731,47 @@ vc_buf[rg] = nval; static SIM_INLINE void vc_invalidate (uint32 y1, uint32 y2) { uint32 ln; + +if ((!vc_input_captured) && (!(vc_dev.dctrl & DBG_CURSOR))) + return; for (ln = y1; ln < y2; ln++) - vc_map[ln] = vc_map[ln] & ~VCMAP_VLD; /* invalidate map entry */ + vc_map[ln] &= ~VCMAP_VLD; /* invalidate map entry */ +} + +static void vc_set_vid_cursor (t_bool visible, int func, uint8 *cur_bits) +{ +uint8 data[2*16]; +uint8 mask[2*16]; +int i, d, m; + +sim_debug (DBG_CURSOR, &vc_dev, "vc_set_vid_cursor(%s, %s)\n", visible ? "Visible" : "Invisible", func ? "OR" : "AND"); +memset (data, 0, sizeof(data)); +memset (mask, 0, sizeof(mask)); +for (i=0; i<16*16; i++) { + if (func) { /* OR */ + if (cur_bits[i]) { + /* White */ + d = 0; m = 1; + } + else { + /* Transparent */ + d = 0; m = 0; + } + } + else { /* AND */ + if (cur_bits[i]) { + /* Black */ + d = 1; m = 1; + } + else { + /* Transparent */ + d = 0; m = 0; + } + } + data[i>>3] |= d<<(7-(i&7)); + mask[i>>3] |= m<<(7-(i&7)); + } +vid_set_cursor (visible, 16, 16, data, mask); } void vc_checkint (void) @@ -738,7 +857,7 @@ return 0; /* no intr req */ t_stat vc_svc (UNIT *uptr) { t_bool updated = FALSE; /* flag for refresh */ -uint32 line[1024]; +uint32 line; uint32 ln, col, off; int32 xpos, ypos, dx, dy; uint8 *cur; @@ -756,19 +875,30 @@ else if (vc_cur_y != CUR_Y) { /* moved (Y)? */ vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ vc_invalidate (vc_cur_y, (vc_cur_y + 16)); /* invalidate old pos */ } -else if ((vc_cur_x != CUR_X) || (vc_cur_f != CUR_F)) { /* moved (X) or mask changed? */ +else if ((vc_cur_x != CUR_X) || /* moved (X)? or */ + (vc_cur_f != CUR_F) || /* mask changed? or */ + (vc_cur_new_data)) { /* cursor image changed? */ vc_invalidate (CUR_Y, (CUR_Y + 16)); /* invalidate new pos */ } -vid_cursor_x = vc_cur_x = CUR_X; /* store cursor data */ -vid_cursor_y = vc_cur_y = CUR_Y; +if ((!vc_input_captured) && /* OS cursor? AND*/ + ((vc_cur_f != CUR_F) || /* (mask changed? OR */ + (vc_cur_new_data) || /* cursor image changed? OR) */ + (vc_cur_v != CUR_V))) { /* visibility changed?) */ + vc_set_vid_cursor (CUR_V, CUR_F, vc_cur); + } + +vc_cur_x = CUR_X; /* store cursor data */ +vc_cur_y = CUR_Y; +vid_set_cursor_position (vc_cur_x, vc_cur_y); vc_cur_v = CUR_V; vc_cur_f = CUR_F; +vc_cur_new_data = FALSE; xpos = vc_mpos & 0xFF; /* get current mouse position */ ypos = (vc_mpos >> 8) & 0xFF; dx = vid_mouse_xrel; /* get relative movement */ -dy = vid_mouse_yrel; +dy = -vid_mouse_yrel; if (dx > VC_MOVE_MAX) /* limit movement */ dx = VC_MOVE_MAX; else if (dx < -VC_MOVE_MAX) @@ -780,8 +910,8 @@ else if (dy < -VC_MOVE_MAX) xpos += dx; /* add to counters */ ypos += dy; vc_mpos = ((ypos & 0xFF) << 8) | (xpos & 0xFF); /* update register */ -vid_mouse_xrel = 0; /* reset counters for next poll */ -vid_mouse_yrel = 0; +vid_mouse_xrel -= dx; /* reset counters for next poll */ +vid_mouse_yrel += dy; vc_csr |= (CSR_MSA | CSR_MSB | CSR_MSC); /* reset button states */ if (vid_mouse_b3) /* set new button states */ @@ -791,28 +921,36 @@ if (vid_mouse_b2) if (vid_mouse_b1) vc_csr &= ~CSR_MSC; +line = 0; for (ln = 0; ln < VC_YSIZE; ln++) { if ((vc_map[ln] & VCMAP_VLD) == 0) { /* line invalid? */ - off = vc_map[ln] * 32; /* get video buf offet */ - for (col = 0; col < 1024; col++) - line[col] = vid_mono_palette[(vc_buf[off + (col >> 5)] >> (col & 0x1F)) & 1]; + off = vc_map[ln] * 32; /* get video buf offset */ + for (col = 0; col < VC_XSIZE; col++) + vc_lines[line*VC_XSIZE + col] = vid_mono_palette[(vc_buf[off + (col >> 5)] >> (col & 0x1F)) & 1]; /* 1bpp to 32bpp */ - if (CUR_V) { /* cursor visible? */ + if (CUR_V && /* cursor visible && need to draw cursor? */ + (vc_input_captured || (vc_dev.dctrl & DBG_CURSOR))) { if ((ln >= CUR_Y) && (ln < (CUR_Y + 16))) { /* cursor on this line? */ cur = &vc_cur[((ln - CUR_Y) << 4)]; /* get image base */ for (col = 0; col < 16; col++) { - if ((CUR_X + col) >= 1024) /* Part of cursor off screen? */ + if ((CUR_X + col) >= VC_XSIZE) /* Part of cursor off screen? */ continue; /* Skip */ if (CUR_F) /* mask function */ - line[CUR_X + col] = vid_mono_palette[(line[CUR_X + col] == vid_mono_palette[1]) | (cur[col] & 1)]; + vc_lines[line*VC_XSIZE + CUR_X + col] = vid_mono_palette[(vc_lines[line*VC_XSIZE + CUR_X + col] == vid_mono_palette[1]) | (cur[col] & 1)]; else - line[CUR_X + col] = vid_mono_palette[(line[CUR_X + col] == vid_mono_palette[1]) & (~cur[col] & 1)]; + vc_lines[line*VC_XSIZE + CUR_X + col] = vid_mono_palette[(vc_lines[line*VC_XSIZE + CUR_X + col] == vid_mono_palette[1]) & (~cur[col] & 1)]; } } } - vid_draw (0, ln, 1024, 1, &line[0]); /* update line */ + vc_map[ln] |= VCMAP_VLD; /* set valid */ + if ((ln == (VC_YSIZE-1)) || /* if end of window OR */ + (vc_map[ln+1] & VCMAP_VLD)) { /* next is already valid? */ + vid_draw (0, ln-line, VC_XSIZE, line+1, (uint32*)vc_lines); /* update region */ + line = 0; + } + else + line++; updated = TRUE; - vc_map[ln] = vc_map[ln] | VCMAP_VLD; /* set valid */ } } @@ -854,11 +992,15 @@ vc_crtc_p = (CRTCP_LPF | CRTCP_VB); if (dptr->flags & DEV_DIS) { free (vc_buf); vc_buf = NULL; + free (vc_lines); + vc_lines = NULL; + free (vc_map); + vc_map = NULL; return vid_close (); } if (!vid_active) { - r = vid_open (dptr, VC_XSIZE, VC_YSIZE); /* display size */ + r = vid_open (dptr, VC_XSIZE, VC_YSIZE, vc_input_captured ? SIM_VID_INPUTCAPTURED : 0);/* display size & capture mode */ if (r != SCPE_OK) return r; vc_buf = (uint32 *) calloc (VC_MEMSIZE, sizeof (uint32)); @@ -866,10 +1008,24 @@ if (!vid_active) { vid_close (); return SCPE_MEM; } + vc_lines = (uint32 *) calloc (VC_XSIZE*VC_YSIZE, sizeof (uint32)); + if (vc_lines == NULL) { + free (vc_buf); + vid_close (); + return SCPE_MEM; + } + vc_map = (uint32 *) calloc (VC_XSIZE, sizeof (uint32)); + if (vc_map == NULL) { + free (vc_lines); + vc_lines = NULL; + free (vc_buf); + vid_close (); + return SCPE_MEM; + } sim_printf ("QVSS Display Created. "); - vid_show_release_key (stdout, NULL, 0, NULL); + vc_show_capture (stdout, NULL, 0, NULL); if (sim_log) - vid_show_release_key (sim_log, NULL, 0, NULL); + vc_show_capture (sim_log, NULL, 0, NULL); sim_printf ("\n"); } sim_activate_abs (&vc_unit, tmxr_poll); @@ -881,6 +1037,25 @@ t_stat vc_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc) return cpu_set_model (NULL, 0, (val ? "VAXSTATION" : "MICROVAX"), NULL); } +t_stat vc_set_capture (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (vid_active) + return sim_messagef (SCPE_ALATT, "Capture Mode Can't be changed with device enabled\n"); +vc_input_captured = val; +return SCPE_OK; +} + +t_stat vc_show_capture (FILE* st, UNIT* uptr, int32 val, void* desc) +{ +if (vc_input_captured) { + fprintf (st, "Captured Input Mode, "); + vid_show_release_key (st, uptr, val, desc); + } +else + fprintf (st, "Uncaptured Input Mode"); +return SCPE_OK; +} + t_stat vc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { fprintf (st, "VCB01 Monochrome Video Subsystem (%s)\n\n", dptr->name); diff --git a/VAX/vax_vs.c b/VAX/vax_vs.c index a8a55d71..1d3946d2 100644 --- a/VAX/vax_vs.c +++ b/VAX/vax_vs.c @@ -140,7 +140,7 @@ switch (vs_state) { case VSXXX_SEND: case VSXXX_TEST: *c = vs_buf[vs_bptr++]; - sim_debug (DBG_SERIAL, &vs_dev, "mouse -> vax: %02X\n", *c); + sim_debug (DBG_SERIAL, &vs_dev, "mouse -> vax: 0x%02X\n", *c); if (vs_bptr == vs_datalen) { vs_state = VSXXX_IDLE; } @@ -197,16 +197,27 @@ return SCPE_OK; void vs_sendupd (void) { vs_buf[0] = RPT_SYNC; -vs_buf[0] |= (((vs_x >= 0) ? 1 : 0) << 4); /* sign bits */ -vs_buf[0] |= (((vs_y >= 0) ? 1 : 0) << 3); +vs_buf[0] |= (((vs_x > 0) ? 1 : 0) << 4); /* sign bits */ +vs_buf[0] |= (((vs_y >= 0) ? 0 : 1) << 3); vs_buf[0] |= (((vs_l) ? 1 : 0) << 2); /* button states */ vs_buf[0] |= (((vs_m) ? 1 : 0) << 1); vs_buf[0] |= ((vs_r) ? 1 : 0); -vs_buf[1] = (abs(vs_x)) & 0x7F; /* motion */ -vs_buf[2] = (abs(vs_y)) & 0x7F; +vs_buf[1] = (abs(vs_x) > 0x3F) ? 0x3F : abs(vs_x); /* motion (limited to 63 pixels in any direction) */ +if (vs_x > 0) + vs_x -= vs_buf[1]; +else + vs_x += vs_buf[1]; +vs_buf[2] = (abs(vs_y) > 0x3F) ? 0x3F : abs(vs_y); +if (vs_y > 0) + vs_y -= vs_buf[2]; +else + vs_y += vs_buf[2]; vs_bptr = 0; vs_state = VSXXX_SEND; vs_datalen = 3; +sim_debug (DBG_SERIAL, &vs_dev, "mouse motion queued for delivery: Motion:(%s%d,%s%d), Buttons:(%s,%s,%s) Remnant skipped:(%d,%d)\n", + (vs_buf[0]&0x10) ? "s" : "", vs_buf[1], (vs_buf[0]&0x08) ? "s" : "", vs_buf[2], (vs_buf[0]&0x04) ? "L" : "l", (vs_buf[0]&0x02) ? "M" : "m", (vs_buf[0]&0x01) ? "R" : "r", vs_x, vs_y); +vs_x = vs_y = 0; } void vs_poll (void) @@ -216,6 +227,9 @@ SIM_MOUSE_EVENT ev; if (vid_poll_mouse (&ev) != SCPE_OK) return; if (vs_state == VSXXX_IDLE) { + if ((ev.x_rel == 0) && (ev.y_rel == 0) && + (vs_l == ev.b1_state) && (vs_m == ev.b2_state) && (vs_r == ev.b3_state)) + return; vs_x = ev.x_rel; vs_y = ev.y_rel; vs_l = ev.b1_state; diff --git a/sim_video.c b/sim_video.c index f92b74b9..6c01235a 100644 --- a/sim_video.c +++ b/sim_video.c @@ -32,13 +32,14 @@ #include "sim_video.h" t_bool vid_active = FALSE; -int32 vid_mouse_xrel = 0; -int32 vid_mouse_yrel = 0; +int32 vid_mouse_xrel; +int32 vid_mouse_yrel; int32 vid_cursor_x; int32 vid_cursor_y; t_bool vid_mouse_b1 = FALSE; t_bool vid_mouse_b2 = FALSE; t_bool vid_mouse_b3 = FALSE; +char vid_release_key[64] = "Ctrl-Right-Shift"; #if HAVE_LIBSDL #include @@ -46,6 +47,8 @@ t_bool vid_mouse_b3 = FALSE; #define EVENT_REDRAW 1 /* redraw event for SDL */ #define EVENT_CLOSE 2 /* close event for SDL */ +#define EVENT_CURSOR 3 /* new cursor for SDL */ +#define EVENT_WARP 4 /* warp mouse position for SDL */ #define MAX_EVENTS 20 /* max events in queue */ typedef struct { @@ -67,37 +70,52 @@ typedef struct { int vid_thread (void* arg); /* - Currently there are two separate video implementations which exist - due to the fact that libSDL and libSDL2 provide vastly different APIs. + libSDL and libSDL2 have significantly different APIs. + The consequence is that this code has significant #ifdef sections. - libSDL2 is the distinctly better choice going forward, and, given the - background thread event digestion, is the only one which will work on - OSX. + The current structure is to implement the API differences in each + routine that has a difference. This allows the decision and flow + logic to exist once and thus to allow logic changes to be implemented + in one place. - We will abandon libSDL (Version 1) completely when the libSDL2 developer - components are readily packaged for most Linux distributions. */ -#if SDL_MAJOR_VERSION == 1 -t_bool vid_key_state[SDLK_LAST]; t_bool vid_mouse_captured; +int32 vid_flags; /* Open Flags */ int32 vid_width; int32 vid_height; +t_bool vid_ready; +#if SDL_MAJOR_VERSION == 1 +t_bool vid_key_state[SDLK_LAST]; SDL_Surface *vid_image; /* video buffer */ SDL_Surface *vid_window; /* window handle */ +#else +t_bool vid_key_state[SDL_NUM_SCANCODES]; +SDL_Texture *vid_texture; /* video buffer in GPU */ +SDL_Renderer *vid_renderer; +SDL_Window *vid_window; /* window handle */ +uint32 vid_windowID; +#endif SDL_Thread *vid_thread_handle; /* event thread handle */ -uint32 vid_mono_palette[2]; +SDL_Cursor *vid_cursor; /* current cursor */ +t_bool vid_cursor_visible = FALSE; /* cursor visibility state */ +uint32 vid_mono_palette[2]; /* Monochrome Color Map */ +SDL_Color vid_colors[256]; KEY_EVENT_QUEUE vid_key_events; /* keyboard events */ MOUSE_EVENT_QUEUE vid_mouse_events; /* mouse events */ DEVICE *vid_dev; -t_stat vid_open (DEVICE *dptr, uint32 width, uint32 height) +t_stat vid_open (DEVICE *dptr, uint32 width, uint32 height, int flags) { if (!vid_active) { + int wait_count = 0; + + vid_flags = flags; vid_active = TRUE; vid_width = width; vid_height = height; vid_mouse_captured = FALSE; + vid_cursor_visible = (vid_flags & SIM_VID_INPUTCAPTURED); vid_mouse_xrel = 0; vid_mouse_yrel = 0; @@ -112,12 +130,23 @@ if (!vid_active) { vid_dev = dptr; + vid_ready = FALSE; +#if SDL_MAJOR_VERSION == 1 vid_thread_handle = SDL_CreateThread (vid_thread, NULL); +#else + vid_thread_handle = SDL_CreateThread (vid_thread, "vid-thread", NULL); +#endif if (vid_thread_handle == NULL) { vid_close (); return SCPE_OPENERR; } - + while ((!vid_ready) && (++wait_count < 20)) + sim_os_ms_sleep (100); + if (!vid_ready) { + vid_close (); + return SCPE_OPENERR; + } + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_open() - Success\n"); } return SCPE_OK; @@ -172,41 +201,158 @@ return SCPE_EOF; t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev) { +t_stat stat = SCPE_EOF; +SIM_MOUSE_EVENT *nev; + if (SDL_SemTryWait (vid_mouse_events.sem) == 0) { if (vid_mouse_events.count > 0) { + stat = SCPE_OK; *ev = vid_mouse_events.events[vid_mouse_events.head++]; vid_mouse_events.count--; if (vid_mouse_events.head == MAX_EVENTS) vid_mouse_events.head = 0; - SDL_SemPost (vid_mouse_events.sem); - return SCPE_OK; + nev = &vid_mouse_events.events[vid_mouse_events.head]; + if ((vid_mouse_events.count > 0) && + (0 == (ev->x_rel + nev->x_rel)) && + (0 == (ev->y_rel + nev->y_rel)) && + (ev->b1_state == nev->b1_state) && + (ev->b2_state == nev->b2_state) && + (ev->b3_state == nev->b3_state)) { + if ((++vid_mouse_events.head) == MAX_EVENTS) + vid_mouse_events.head = 0; + vid_mouse_events.count--; + stat = SCPE_EOF; + sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "vid_poll_mouse: ignoring bouncing events\n"); + } } - SDL_SemPost (vid_mouse_events.sem); + if (SDL_SemPost (vid_mouse_events.sem)) + sim_printf ("%s: vid_poll_mouse(): SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError()); } -return SCPE_EOF; +return stat; } void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf) { +#if SDL_MAJOR_VERSION == 1 int32 i; uint32* pixels; +sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_draw(%d, %d, %d, %d)\n", x, y, w, h); + pixels = (uint32 *)vid_image->pixels; -for (i = y; i < (y + h); i++) - memcpy (pixels + (i * vid_width) + x, buf, (size_t)w*sizeof(*pixels)); +for (i = 0; i < h; i++) + memcpy (pixels + ((i + y) * vid_width) + x, buf + w*i, w*sizeof(*pixels)); +#else +SDL_Rect vid_dst; + +vid_dst.x = x; +vid_dst.y = y; +vid_dst.w = w; +vid_dst.h = h; + +sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_draw(%d, %d, %d, %d)\n", x, y, w, h); + +if (SDL_UpdateTexture(vid_texture, &vid_dst, buf, w*sizeof(*buf))) + sim_printf ("%s: vid_draw() - SDL_UpdateTexture error: %s\n", sim_dname(vid_dev), SDL_GetError()); +#endif +} + +t_stat vid_set_cursor (t_bool visible, uint32 width, uint32 height, uint8 *data, uint8 *mask) +{ +SDL_Cursor *cursor = SDL_CreateCursor (data, mask, width, height, 0, 0); +SDL_Event user_event; + +sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor(%s, %d, %d) Setting New Cursor\n", visible ? "visible" : "invisible", width, height); +if (sim_deb) { + uint32 i, j; + + for (i=0; i> 3; + int bit = 7 - ((j + i*width) & 0x7); + static char mode[] = "TWIB"; + + sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "%c", mode[(((data[byte]>>bit)&1)<<1)|(mask[byte]>>bit)&1]); + } + sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "\n"); + } + } + +user_event.type = SDL_USEREVENT; +user_event.user.code = EVENT_CURSOR; +user_event.user.data1 = cursor; +user_event.user.data2 = (void *)((size_t)visible); + +if (SDL_PushEvent (&user_event) < 0) + sim_printf ("%s: vid_set_cursor() SDL_PushEvent error: %s\n", sim_dname(vid_dev), SDL_GetError()); + +return SCPE_OK; +} + +void vid_set_cursor_position (int32 x, int32 y) +{ +int32 x_delta = vid_cursor_x - x; +int32 y_delta = vid_cursor_y - y; + +if ((x_delta) || (y_delta)) { + sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position(%d, %d) - Cursor position changed\n", x, y); + /* Any queued mouse motion events need to have their relative + positions adjusted since they were queued based on different info. */ + if (SDL_SemWait (vid_mouse_events.sem) == 0) { + int32 i; + SIM_MOUSE_EVENT *ev; + + for (i=0; ix_rel, ev->y_rel, ev->x_rel + x_delta, ev->y_rel + y_delta); + vid_mouse_xrel -= ev->x_rel; /* remove previously accumulated relative position */ + vid_mouse_yrel -= ev->y_rel; + ev->x_rel += x_delta; + ev->y_rel += y_delta; + vid_mouse_xrel += ev->x_rel; /* update cumulative x & y rel */ + vid_mouse_yrel += ev->y_rel; + } + if (SDL_SemPost (vid_mouse_events.sem)) + sim_printf ("%s: vid_set_cursor_position(): SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError()); + } + else { + sim_printf ("%s: vid_set_cursor_position(): SDL_SemWait error: %s\n", sim_dname(vid_dev), SDL_GetError()); + } + vid_cursor_x = x; + vid_cursor_y = y; + if (vid_cursor_visible) { + SDL_Event user_event; + + user_event.type = SDL_USEREVENT; + user_event.user.code = EVENT_WARP; + user_event.user.data1 = NULL; + user_event.user.data2 = NULL; + + if (SDL_PushEvent (&user_event) < 0) + sim_printf ("%s: vid_set_cursor_position() SDL_PushEvent error: %s\n", sim_dname(vid_dev), SDL_GetError()); + sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position() - Warp Queued\n"); + } + else { + sim_debug (SIM_VID_DBG_CURSOR, vid_dev, "vid_set_cursor_position() - Warp Skipped\n"); + } + } } void vid_refresh (void) { SDL_Event user_event; +sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_refresh() - Queueing Refresh Event\n"); + user_event.type = SDL_USEREVENT; user_event.user.code = EVENT_REDRAW; user_event.user.data1 = NULL; user_event.user.data2 = NULL; -SDL_PushEvent (&user_event); +if (SDL_PushEvent (&user_event) < 0) + sim_printf ("%s: vid_refresh() SDL_PushEvent error: %s\n", sim_dname(vid_dev), SDL_GetError()); } int vid_map_key (int key) @@ -222,9 +368,6 @@ switch (key) { case SDLK_RETURN: return SIM_KEY_ENTER; - case SDLK_PAUSE: - return SIM_KEY_PAUSE; - case SDLK_ESCAPE: return SIM_KEY_ESC; @@ -374,7 +517,7 @@ switch (key) { case SDLK_DELETE: return SIM_KEY_DELETE; - +#if SDL_MAJOR_VERSION == 1 case SDLK_KP0: return SIM_KEY_KP_INSERT; @@ -404,703 +547,7 @@ switch (key) { case SDLK_KP9: return SIM_KEY_KP_PAGE_UP; - - case SDLK_KP_PERIOD: - return SIM_KEY_KP_DELETE; - - case SDLK_KP_DIVIDE: - return SIM_KEY_KP_DIVIDE; - - case SDLK_KP_MULTIPLY: - return SIM_KEY_KP_MULTIPLY; - - case SDLK_KP_MINUS: - return SIM_KEY_KP_SUBTRACT; - - case SDLK_KP_PLUS: - return SIM_KEY_KP_ADD; - - case SDLK_KP_ENTER: - return SIM_KEY_KP_ENTER; - - case SDLK_UP: - return SIM_KEY_UP; - - case SDLK_DOWN: - return SIM_KEY_DOWN; - - case SDLK_RIGHT: - return SIM_KEY_RIGHT; - - case SDLK_LEFT: - return SIM_KEY_LEFT; - - case SDLK_INSERT: - return SIM_KEY_INSERT; - - case SDLK_HOME: - return SIM_KEY_HOME; - - case SDLK_END: - return SIM_KEY_END; - - case SDLK_PAGEUP: - return SIM_KEY_PAGE_UP; - - case SDLK_PAGEDOWN: - return SIM_KEY_PAGE_DOWN; - - case SDLK_F1: - return SIM_KEY_F1; - - case SDLK_F2: - return SIM_KEY_F2; - - case SDLK_F3: - return SIM_KEY_F3; - - case SDLK_F4: - return SIM_KEY_F4; - - case SDLK_F5: - return SIM_KEY_F5; - - case SDLK_F6: - return SIM_KEY_F6; - - case SDLK_F7: - return SIM_KEY_F7; - - case SDLK_F8: - return SIM_KEY_F8; - - case SDLK_F9: - return SIM_KEY_F9; - - case SDLK_F10: - return SIM_KEY_F10; - - case SDLK_F11: - return SIM_KEY_F11; - - case SDLK_F12: - return SIM_KEY_F12; - - case SDLK_NUMLOCK: - return SIM_KEY_NUM_LOCK; - - case SDLK_CAPSLOCK: - return SIM_KEY_CAPS_LOCK; - - case SDLK_SCROLLOCK: - return SIM_KEY_SCRL_LOCK; - - case SDLK_RSHIFT: - return SIM_KEY_SHIFT_R; - - case SDLK_LSHIFT: - return SIM_KEY_SHIFT_L; - - case SDLK_RCTRL: - return SIM_KEY_CTRL_R; - - case SDLK_LCTRL: - return SIM_KEY_CTRL_L; - - case SDLK_RALT: - return SIM_KEY_ALT_R; - - case SDLK_LALT: - return SIM_KEY_ALT_L; - - case SDLK_RMETA: - return SIM_KEY_ALT_R; - - case SDLK_LMETA: - return SIM_KEY_WIN_L; - - case SDLK_LSUPER: - return SIM_KEY_WIN_L; - - case SDLK_RSUPER: - return SIM_KEY_WIN_R; - - case SDLK_PRINT: - return SIM_KEY_PRINT; - - case SDLK_BREAK: - return SIM_KEY_PAUSE; - - case SDLK_MENU: - return SIM_KEY_MENU; - - default: - return SIM_KEY_UNKNOWN; - } -} - -void vid_key (SDL_KeyboardEvent *event) -{ -SIM_KEY_EVENT ev; - -if (vid_mouse_captured) { - static Uint8 *KeyStates = NULL; - static int numkeys; - - if (!KeyStates) - KeyStates = SDL_GetKeyState(&numkeys); - if ((event->state == SDL_PRESSED) && KeyStates[SDLK_RSHIFT] && (KeyStates[SDLK_LCTRL] || KeyStates[SDLK_RCTRL])) { - sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_key() - Cursor Release\n"); - SDL_WM_GrabInput (SDL_GRAB_OFF); /* relese cursor */ - SDL_ShowCursor (SDL_ENABLE); /* show cursor */ - vid_mouse_captured = FALSE; - return; - } - } -if (!sim_is_running) - return; -if (SDL_SemWait (vid_key_events.sem) == 0) { - if (vid_key_events.count < MAX_EVENTS) { - sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event: State: %d, Keysym: %d\n", event->state, event->keysym); - if (event->state == SDL_PRESSED) { - if (!vid_key_state[event->keysym.sym]) { /* Key was not down before */ - vid_key_state[event->keysym.sym] = TRUE; - ev.key = vid_map_key (event->keysym.sym); - ev.state = SIM_KEYPRESS_DOWN; - } - else { - ev.key = vid_map_key (event->keysym.sym); - ev.state = SIM_KEYPRESS_REPEAT; - } - } - else { - vid_key_state[event->keysym.sym] = FALSE; - ev.key = vid_map_key (event->keysym.sym); - ev.state = SIM_KEYPRESS_UP; - } - vid_key_events.events[vid_key_events.tail++] = ev; - vid_key_events.count++; - if (vid_key_events.tail == MAX_EVENTS) - vid_key_events.tail = 0; - } - else { - sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event DISCARDED: State: %d, Keysym: %d\n", event->state, event->keysym); - } - SDL_SemPost (vid_key_events.sem); - } -} - -void vid_mouse_move (SDL_MouseMotionEvent *event) -{ -SDL_Event dummy_event; -SIM_MOUSE_EVENT ev; - -if (!vid_mouse_captured) - return; - -if ((event->x == 0) || - (event->y == 0) || - (event->x == (vid_width - 1)) || - (event->y == (vid_height - 1))) { /* reached edge of window? */ - SDL_PumpEvents (); - while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {}; - SDL_WarpMouse (vid_cursor_x, vid_cursor_y); /* sync position */ - } -if (!sim_is_running) - return; -vid_mouse_xrel += event->xrel; /* update cumulative x rel */ -vid_mouse_yrel -= event->yrel; /* update cumulative y rel */ -vid_mouse_b1 = (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? TRUE : FALSE; -vid_mouse_b2 = (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? TRUE : FALSE; -vid_mouse_b3 = (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? TRUE : FALSE; -if (SDL_SemWait (vid_mouse_events.sem) == 0) { - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: (%d,%d)\n", event->xrel, event->yrel); - if (vid_mouse_events.count < MAX_EVENTS) { - ev.x_rel = event->xrel; - ev.y_rel = (-event->yrel); - ev.b1_state = vid_mouse_b1; - ev.b2_state = vid_mouse_b2; - ev.b3_state = vid_mouse_b3; - vid_mouse_events.events[vid_mouse_events.tail++] = ev; - vid_mouse_events.count++; - if (vid_mouse_events.tail == MAX_EVENTS) - vid_mouse_events.tail = 0; - } - SDL_SemPost (vid_mouse_events.sem); - } -} - -void vid_mouse_button (SDL_MouseButtonEvent *event) -{ -SDL_Event dummy_event; -SIM_MOUSE_EVENT ev; -t_bool state; - -if (!vid_mouse_captured) { - if ((event->state == SDL_PRESSED) && - (event->button == SDL_BUTTON_LEFT)) { /* left click and cursor not captured? */ - sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_mouse_button() - Cursor Captured\n"); - SDL_WM_GrabInput (SDL_GRAB_ON); /* lock cursor to window */ - SDL_ShowCursor (SDL_DISABLE); /* hide cursor */ - SDL_PumpEvents (); - while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {}; - SDL_WarpMouse (vid_cursor_x, vid_cursor_y); /* sync position */ - vid_mouse_captured = TRUE; - } - return; - } -if (!sim_is_running) - return; -state = (event->state == SDL_PRESSED) ? TRUE : FALSE; -switch (event->button) { - case SDL_BUTTON_LEFT: - vid_mouse_b1 = state; - break; - case SDL_BUTTON_MIDDLE: - vid_mouse_b2 = state; - break; - case SDL_BUTTON_RIGHT: - vid_mouse_b3 = state; - break; - } -if (SDL_SemWait (vid_mouse_events.sem) == 0) { - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event: State: %d, Button: %d, (%d,%d)\n", event->state, event->button, event->x, event->y); - if (vid_mouse_events.count < MAX_EVENTS) { - ev.x_rel = 0; - ev.y_rel = 0; - ev.b1_state = vid_mouse_b1; - ev.b2_state = vid_mouse_b2; - ev.b3_state = vid_mouse_b3; - vid_mouse_events.events[vid_mouse_events.tail++] = ev; - vid_mouse_events.count++; - if (vid_mouse_events.tail == MAX_EVENTS) - vid_mouse_events.tail = 0; - } - SDL_SemPost (vid_mouse_events.sem); - } -} - -void vid_update (void) -{ -SDL_Rect vid_dst; - -vid_dst.x = 0; -vid_dst.y = 0; -vid_dst.w = vid_width; -vid_dst.h = vid_height; - -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Video Update Event: \n"); -SDL_BlitSurface (vid_image, NULL, vid_window, &vid_dst); -SDL_UpdateRects (vid_window, 1, &vid_dst); -} - -int vid_thread (void* arg) -{ -SDL_Event event; -static char *eventtypes[] = { - "NOEVENT", /**< Unused (do not remove) */ - "ACTIVEEVENT", /**< Application loses/gains visibility */ - "KEYDOWN", /**< Keys pressed */ - "KEYUP", /**< Keys released */ - "MOUSEMOTION", /**< Mouse moved */ - "MOUSEBUTTONDOWN", /**< Mouse button pressed */ - "MOUSEBUTTONUP", /**< Mouse button released */ - "JOYAXISMOTION", /**< Joystick axis motion */ - "JOYBALLMOTION", /**< Joystick trackball motion */ - "JOYHATMOTION", /**< Joystick hat position change */ - "JOYBUTTONDOWN", /**< Joystick button pressed */ - "JOYBUTTONUP", /**< Joystick button released */ - "QUIT", /**< User-requested quit */ - "SYSWMEVENT", /**< System specific event */ - "EVENT_RESERVEDA", /**< Reserved for future use.. */ - "EVENT_RESERVEDB", /**< Reserved for future use.. */ - "VIDEORESIZE", /**< User resized video mode */ - "VIDEOEXPOSE", /**< Screen needs to be redrawn */ - "EVENT_RESERVED2", /**< Reserved for future use.. */ - "EVENT_RESERVED3", /**< Reserved for future use.. */ - "EVENT_RESERVED4", /**< Reserved for future use.. */ - "EVENT_RESERVED5", /**< Reserved for future use.. */ - "EVENT_RESERVED6", /**< Reserved for future use.. */ - "EVENT_RESERVED7", /**< Reserved for future use.. */ - "USEREVENT", /** Events SDL_USEREVENT(24) through SDL_MAXEVENTS-1(31) are for your use */ - "", - "", - "", - "", - "", - "", - "" - }; - -sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Starting\n"); - -SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE); - -vid_window = SDL_SetVideoMode (vid_width, vid_height, 8, 0); - -SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - -if (sim_end) - vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); -else - vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); - -vid_mono_palette[0] = sim_end ? 0xFF000000 : 0x000000FF; -vid_mono_palette[1] = 0xFFFFFFFF; - - -SDL_WM_SetCaption (&sim_name[0], &sim_name[0]); - -memset (&vid_key_state, 0, sizeof(vid_key_state)); - -sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Started\n"); - -while (vid_active) { - if (SDL_WaitEvent (&event)) { - switch (event.type) { - - case SDL_KEYDOWN: - case SDL_KEYUP: - vid_key ((SDL_KeyboardEvent*)&event); - break; - - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - vid_mouse_button ((SDL_MouseButtonEvent*)&event); - break; - - case SDL_MOUSEMOTION: - vid_mouse_move ((SDL_MouseMotionEvent*)&event); - break; - - case SDL_USEREVENT: - if (event.user.code == EVENT_REDRAW) - vid_update (); - break; - - default: - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Ignored Event: Type: %s(%d)\n", eventtypes[event.type], event.type); - break; - } - } - } -SDL_Quit (); -sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Exiting\n"); -return 0; -} -#else /* libSDL2 implementation */ -t_bool vid_key_state[SDL_NUM_SCANCODES]; -t_bool vid_mouse_captured; -int32 vid_width; -int32 vid_height; -SDL_Texture *vid_texture; /* video buffer in GPU */ -SDL_Window *vid_window; /* window handle */ -SDL_Renderer *vid_renderer; -SDL_Thread *vid_thread_handle; /* event thread handle */ -uint32 vid_mono_palette[2]; /* Monochrome Color Map */ -SDL_Color vid_colors[256]; -KEY_EVENT_QUEUE vid_key_events; /* keyboard events */ -MOUSE_EVENT_QUEUE vid_mouse_events; /* mouse events */ -DEVICE *vid_dev; - -t_stat vid_open (DEVICE *dptr, uint32 width, uint32 height) -{ -if (!vid_active) { - int wait_count = 0; - - vid_active = TRUE; - vid_width = width; - vid_height = height; - vid_mouse_captured = FALSE; - vid_mouse_xrel = 0; - vid_mouse_yrel = 0; - - vid_key_events.head = 0; - vid_key_events.tail = 0; - vid_key_events.count = 0; - vid_key_events.sem = SDL_CreateSemaphore (1); - vid_mouse_events.head = 0; - vid_mouse_events.tail = 0; - vid_mouse_events.count = 0; - vid_mouse_events.sem = SDL_CreateSemaphore (1); - - vid_dev = dptr; - - vid_thread_handle = SDL_CreateThread (vid_thread, "vid-thread", NULL); - if (vid_thread_handle == NULL) { - vid_close (); - return SCPE_OPENERR; - } - while ((!vid_texture) && (++wait_count < 20)) - sim_os_ms_sleep (100); - if (!vid_texture) { - vid_close (); - return SCPE_OPENERR; - } - - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_open() - Success\n"); - } -return SCPE_OK; -} - -t_stat vid_close (void) -{ -SDL_Event user_event; -int status; - -if (vid_active) { - vid_active = FALSE; - if (vid_thread_handle) { - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_close()\n"); - user_event.type = SDL_USEREVENT; - user_event.user.code = EVENT_CLOSE; - user_event.user.data1 = NULL; - user_event.user.data2 = NULL; - - SDL_PushEvent (&user_event); - SDL_WaitThread (vid_thread_handle, &status); - vid_thread_handle = NULL; - vid_dev = NULL; - } - if (vid_mouse_events.sem) { - SDL_DestroySemaphore(vid_mouse_events.sem); - vid_mouse_events.sem = NULL; - } - if (vid_key_events.sem) { - SDL_DestroySemaphore(vid_key_events.sem); - vid_key_events.sem = NULL; - } - } -return SCPE_OK; -} - -t_stat vid_poll_kb (SIM_KEY_EVENT *ev) -{ -if (SDL_SemTryWait (vid_key_events.sem) == 0) { /* get lock */ - if (vid_key_events.count > 0) { /* events in queue? */ - *ev = vid_key_events.events[vid_key_events.head++]; - vid_key_events.count--; - if (vid_key_events.head == MAX_EVENTS) - vid_key_events.head = 0; - SDL_SemPost (vid_key_events.sem); - return SCPE_OK; - } - SDL_SemPost (vid_key_events.sem); - } -return SCPE_EOF; -} - -t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev) -{ -if (SDL_SemTryWait (vid_mouse_events.sem) == 0) { - if (vid_mouse_events.count > 0) { - *ev = vid_mouse_events.events[vid_mouse_events.head++]; - vid_mouse_events.count--; - if (vid_mouse_events.head == MAX_EVENTS) - vid_mouse_events.head = 0; - SDL_SemPost (vid_mouse_events.sem); - return SCPE_OK; - } - SDL_SemPost (vid_mouse_events.sem); - } -return SCPE_EOF; -} - -void vid_draw (int32 x, int32 y, int32 w, int32 h, uint32 *buf) -{ -SDL_Rect vid_dst; - -vid_dst.x = x; -vid_dst.y = y; -vid_dst.w = w; -vid_dst.h = h; - -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_draw(%d, %d, %d, %d)\n", x, y, w, h); - -if (SDL_UpdateTexture(vid_texture, &vid_dst, buf, w*sizeof(*buf))) { - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_draw() - SDL_UpdateTexture error: %s\n", SDL_GetError()); - } -} - -void vid_refresh (void) -{ -SDL_Event user_event; - -sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_refresh() - Queueing Refresh Event\n"); - -user_event.type = SDL_USEREVENT; -user_event.user.code = EVENT_REDRAW; -user_event.user.data1 = NULL; -user_event.user.data2 = NULL; - -if (SDL_PushEvent (&user_event) < 0) { - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_refresh() SDL_PushEvent error: %s\n", SDL_GetError()); - } -} - -int vid_map_key (int key) -{ -switch (key) { - - case SDLK_BACKSPACE: - return SIM_KEY_BACKSPACE; - - case SDLK_TAB: - return SIM_KEY_TAB; - - case SDLK_RETURN: - return SIM_KEY_ENTER; - - case SDLK_ESCAPE: - return SIM_KEY_ESC; - - case SDLK_SPACE: - return SIM_KEY_SPACE; - - case SDLK_QUOTE: - return SIM_KEY_SINGLE_QUOTE; - - case SDLK_COMMA: - return SIM_KEY_COMMA; - - case SDLK_MINUS: - return SIM_KEY_MINUS; - - case SDLK_PERIOD: - return SIM_KEY_PERIOD; - - case SDLK_SLASH: - return SIM_KEY_SLASH; - - case SDLK_0: - return SIM_KEY_0; - - case SDLK_1: - return SIM_KEY_1; - - case SDLK_2: - return SIM_KEY_2; - - case SDLK_3: - return SIM_KEY_3; - - case SDLK_4: - return SIM_KEY_4; - - case SDLK_5: - return SIM_KEY_5; - - case SDLK_6: - return SIM_KEY_6; - - case SDLK_7: - return SIM_KEY_7; - - case SDLK_8: - return SIM_KEY_8; - - case SDLK_9: - return SIM_KEY_9; - - case SDLK_SEMICOLON: - return SIM_KEY_SEMICOLON; - - case SDLK_EQUALS: - return SIM_KEY_EQUALS; - - case SDLK_LEFTBRACKET: - return SIM_KEY_LEFT_BRACKET; - - case SDLK_BACKSLASH: - return SIM_KEY_BACKSLASH; - - case SDLK_RIGHTBRACKET: - return SIM_KEY_RIGHT_BRACKET; - - case SDLK_BACKQUOTE: - return SIM_KEY_BACKQUOTE; - - case SDLK_a: - return SIM_KEY_A; - - case SDLK_b: - return SIM_KEY_B; - - case SDLK_c: - return SIM_KEY_C; - - case SDLK_d: - return SIM_KEY_D; - - case SDLK_e: - return SIM_KEY_E; - - case SDLK_f: - return SIM_KEY_F; - - case SDLK_g: - return SIM_KEY_G; - - case SDLK_h: - return SIM_KEY_H; - - case SDLK_i: - return SIM_KEY_I; - - case SDLK_j: - return SIM_KEY_J; - - case SDLK_k: - return SIM_KEY_K; - - case SDLK_l: - return SIM_KEY_L; - - case SDLK_m: - return SIM_KEY_M; - - case SDLK_n: - return SIM_KEY_N; - - case SDLK_o: - return SIM_KEY_O; - - case SDLK_p: - return SIM_KEY_P; - - case SDLK_q: - return SIM_KEY_Q; - - case SDLK_r: - return SIM_KEY_R; - - case SDLK_s: - return SIM_KEY_S; - - case SDLK_t: - return SIM_KEY_T; - - case SDLK_u: - return SIM_KEY_U; - - case SDLK_v: - return SIM_KEY_V; - - case SDLK_w: - return SIM_KEY_W; - - case SDLK_x: - return SIM_KEY_X; - - case SDLK_y: - return SIM_KEY_Y; - - case SDLK_z: - return SIM_KEY_Z; - - case SDLK_DELETE: - return SIM_KEY_DELETE; - +#else case SDLK_KP_0: return SIM_KEY_KP_INSERT; @@ -1130,7 +577,7 @@ switch (key) { case SDLK_KP_9: return SIM_KEY_KP_PAGE_UP; - +#endif case SDLK_KP_PERIOD: return SIM_KEY_KP_DELETE; @@ -1211,16 +658,19 @@ switch (key) { case SDLK_F12: return SIM_KEY_F12; - +#if SDL_MAJOR_VERSION != 1 case SDLK_NUMLOCKCLEAR: return SIM_KEY_NUM_LOCK; - +#endif case SDLK_CAPSLOCK: return SIM_KEY_CAPS_LOCK; - +#if SDL_MAJOR_VERSION == 1 + case SDLK_SCROLLOCK: + return SIM_KEY_SCRL_LOCK; +#else case SDLK_SCROLLLOCK: return SIM_KEY_SCRL_LOCK; - +#endif case SDLK_RSHIFT: return SIM_KEY_SHIFT_R; @@ -1238,16 +688,26 @@ switch (key) { case SDLK_LALT: return SIM_KEY_ALT_L; +#if SDL_MAJOR_VERSION == 1 + case SDLK_RMETA: + return SIM_KEY_ALT_R; + case SDLK_LMETA: + return SIM_KEY_WIN_L; +#else case SDLK_LGUI: return SIM_KEY_WIN_L; case SDLK_RGUI: return SIM_KEY_WIN_R; - +#endif +#if SDL_MAJOR_VERSION == 1 + case SDLK_PRINT: + return SIM_KEY_PRINT; +#else case SDLK_PRINTSCREEN: return SIM_KEY_PRINT; - +#endif case SDLK_PAUSE: return SIM_KEY_PAUSE; @@ -1268,10 +728,26 @@ if (vid_mouse_captured) { static int numkeys; if (!KeyStates) +#if SDL_MAJOR_VERSION == 1 + KeyStates = SDL_GetKeyState(&numkeys); + if ((vid_flags & SIM_VID_INPUTCAPTURED) && + (event->state == SDL_PRESSED) && + KeyStates[SDLK_RSHIFT] && + (KeyStates[SDLK_LCTRL] || KeyStates[SDLK_RCTRL])) { +#else KeyStates = SDL_GetKeyboardState(&numkeys); - if ((event->state == SDL_PRESSED) && KeyStates[SDL_SCANCODE_RSHIFT] && (KeyStates[SDL_SCANCODE_LCTRL] || KeyStates[SDL_SCANCODE_RCTRL])) { + if ((vid_flags & SIM_VID_INPUTCAPTURED) && + (event->state == SDL_PRESSED) && + KeyStates[SDL_SCANCODE_RSHIFT] && + (KeyStates[SDL_SCANCODE_LCTRL] || KeyStates[SDL_SCANCODE_RCTRL])) { +#endif sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_key() - Cursor Release\n"); +#if SDL_MAJOR_VERSION == 1 + SDL_WM_GrabInput (SDL_GRAB_OFF); /* relese cursor */ + SDL_ShowCursor (SDL_ENABLE); /* show cursor */ +#else SDL_SetRelativeMouseMode(SDL_FALSE); /* release cursor, show cursor */ +#endif vid_mouse_captured = FALSE; return; } @@ -1282,8 +758,13 @@ if (SDL_SemWait (vid_key_events.sem) == 0) { sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event: State: %d, Keysym(scancode,sym): (%d,%d)\n", event->state, event->keysym.scancode, event->keysym.sym); if (vid_key_events.count < MAX_EVENTS) { if (event->state == SDL_PRESSED) { +#if SDL_MAJOR_VERSION == 1 + if (!vid_key_state[event->keysym.sym]) { /* Key was not down before */ + vid_key_state[event->keysym.sym] = TRUE; +#else if (!vid_key_state[event->keysym.scancode]) { /* Key was not down before */ vid_key_state[event->keysym.scancode] = TRUE; +#endif ev.key = vid_map_key (event->keysym.sym); ev.state = SIM_KEYPRESS_DOWN; } @@ -1293,7 +774,11 @@ if (SDL_SemWait (vid_key_events.sem) == 0) { } } else { +#if SDL_MAJOR_VERSION == 1 + vid_key_state[event->keysym.sym] = FALSE; +#else vid_key_state[event->keysym.scancode] = FALSE; +#endif ev.key = vid_map_key (event->keysym.sym); ev.state = SIM_KEYPRESS_UP; } @@ -1302,56 +787,84 @@ if (SDL_SemWait (vid_key_events.sem) == 0) { if (vid_key_events.tail == MAX_EVENTS) vid_key_events.tail = 0; } - SDL_SemPost (vid_key_events.sem); + else { + sim_debug (SIM_VID_DBG_KEY, vid_dev, "Keyboard Event DISCARDED: State: %d, Keysym: Scancode: %d, Keysym: %d\n", event->state, event->keysym.scancode, event->keysym.sym); + } + if (SDL_SemPost (vid_key_events.sem)) + sim_printf ("%s: vid_key(): SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError()); } } void vid_mouse_move (SDL_MouseMotionEvent *event) { SDL_Event dummy_event; +SDL_MouseMotionEvent *dev = (SDL_MouseMotionEvent *)&dummy_event; SIM_MOUSE_EVENT ev; -if (!vid_mouse_captured) +if ((!vid_mouse_captured) && (vid_flags & SIM_VID_INPUTCAPTURED)) return; -if ((event->x == 0) || - (event->y == 0) || - (event->x == (vid_width - 1)) || - (event->y == (vid_height - 1))) { /* reached edge of window? */ - SDL_PumpEvents (); - while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) {}; - SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y);/* sync position */ - } if (!sim_is_running) return; +if (!vid_cursor_visible) + return; +sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d)\n", + event->x, event->y, event->xrel, event->yrel, (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0); +#if SDL_MAJOR_VERSION == 1 +while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) { +#else while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) { +#endif /* Coalesce motion activity to avoid thrashing */ - event->xrel += ((SDL_MouseMotionEvent *)&dummy_event)->xrel; - event->yrel += ((SDL_MouseMotionEvent *)&dummy_event)->yrel; - event->x = ((SDL_MouseMotionEvent *)&dummy_event)->x; - event->y = ((SDL_MouseMotionEvent *)&dummy_event)->y; - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: Additional Event Coalesced:(%d,%d) rel:(%d,%d)\n", ((SDL_MouseMotionEvent *)&dummy_event)->x, ((SDL_MouseMotionEvent *)&dummy_event)->y, ((SDL_MouseMotionEvent *)&dummy_event)->xrel, ((SDL_MouseMotionEvent *)&dummy_event)->yrel, vid_mouse_events.count, vid_mouse_xrel, vid_mouse_yrel); + event->xrel += dev->xrel; + event->yrel += dev->yrel; + event->x = dev->x; + event->y = dev->y; + event->state ^= dev->state; + sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: Additional Event Coalesced:pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d)\n", + dev->x, dev->y, dev->xrel, dev->yrel, (dev->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (dev->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (dev->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0); }; -SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y);/* sync position */ -vid_mouse_xrel += event->xrel; /* update cumulative x rel */ -vid_mouse_yrel -= event->yrel; /* update cumulative y rel */ -vid_mouse_b1 = (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? TRUE : FALSE; -vid_mouse_b2 = (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? TRUE : FALSE; -vid_mouse_b3 = (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? TRUE : FALSE; if (SDL_SemWait (vid_mouse_events.sem) == 0) { - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) - Count: %d vid_mouse_rel:(%d,%d)\n", event->x, event->y, event->xrel, event->yrel, vid_mouse_events.count, vid_mouse_xrel, vid_mouse_yrel); + if (!vid_mouse_captured) { + event->xrel = (event->x - vid_cursor_x); + event->yrel = (event->y - vid_cursor_y); + } + vid_mouse_xrel += event->xrel; /* update cumulative x rel */ + vid_mouse_yrel += event->yrel; /* update cumulative y rel */ + vid_mouse_b1 = (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? TRUE : FALSE; + vid_mouse_b2 = (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? TRUE : FALSE; + vid_mouse_b3 = (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? TRUE : FALSE; + sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: pos:(%d,%d) rel:(%d,%d) buttons:(%d,%d,%d) - Count: %d vid_mouse_rel:(%d,%d), vid_cursor:(%d,%d)\n", + event->x, event->y, event->xrel, event->yrel, (event->state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0, (event->state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0, vid_mouse_events.count, vid_mouse_xrel, vid_mouse_yrel, vid_cursor_x, vid_cursor_y); if (vid_mouse_events.count < MAX_EVENTS) { + SIM_MOUSE_EVENT *tail = &vid_mouse_events.events[(vid_mouse_events.tail+MAX_EVENTS-1)%MAX_EVENTS]; + ev.x_rel = event->xrel; - ev.y_rel = (-event->yrel); + ev.y_rel = event->yrel; ev.b1_state = vid_mouse_b1; ev.b2_state = vid_mouse_b2; ev.b3_state = vid_mouse_b3; - vid_mouse_events.events[vid_mouse_events.tail++] = ev; - vid_mouse_events.count++; - if (vid_mouse_events.tail == MAX_EVENTS) - vid_mouse_events.tail = 0; + if ((vid_mouse_events.count > 0) && /* Is there a tail event? */ + (ev.b1_state == tail->b1_state) && /* With the same button state? */ + (ev.b2_state == tail->b2_state) && + (ev.b3_state == tail->b3_state)) { /* Merge the motion */ + tail->x_rel += ev.x_rel; + tail->y_rel += ev.y_rel; + sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event: Coalesced into pending event: (%d,%d) vid_mouse_rel:(%d,%d)\n", + tail->x_rel, tail->y_rel, vid_mouse_xrel, vid_mouse_yrel); + } + else { /* Add a new event */ + vid_mouse_events.events[vid_mouse_events.tail++] = ev; + vid_mouse_events.count++; + if (vid_mouse_events.tail == MAX_EVENTS) + vid_mouse_events.tail = 0; + } } - SDL_SemPost (vid_mouse_events.sem); + else { + sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Move Event Discarded: Count: %d\n", vid_mouse_events.count); + } + if (SDL_SemPost (vid_mouse_events.sem)) + sim_printf ("%s: vid_mouse_move(): SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError()); } } @@ -1361,14 +874,22 @@ SDL_Event dummy_event; SIM_MOUSE_EVENT ev; t_bool state; -if (!vid_mouse_captured) { +if ((!vid_mouse_captured) && (vid_flags & SIM_VID_INPUTCAPTURED)) { if ((event->state == SDL_PRESSED) && (event->button == SDL_BUTTON_LEFT)) { /* left click and cursor not captured? */ sim_debug (SIM_VID_DBG_KEY, vid_dev, "vid_mouse_button() - Cursor Captured\n"); +#if SDL_MAJOR_VERSION == 1 + SDL_WM_GrabInput (SDL_GRAB_ON); /* lock cursor to window */ + SDL_ShowCursor (SDL_DISABLE); /* hide cursor */ + SDL_WarpMouse (vid_width/2, vid_height/2); /* back to center */ + SDL_PumpEvents (); + while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTIONMASK)) {}; +#else SDL_SetRelativeMouseMode(SDL_TRUE); /* lock cursor to window, hide cursor */ + SDL_WarpMouseInWindow (NULL, vid_width/2, vid_height/2);/* back to center */ SDL_PumpEvents (); while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION)) {}; - SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y);/* sync position */ +#endif vid_mouse_captured = TRUE; } return; @@ -1376,18 +897,18 @@ if (!vid_mouse_captured) { if (!sim_is_running) return; state = (event->state == SDL_PRESSED) ? TRUE : FALSE; -switch (event->button) { - case SDL_BUTTON_LEFT: - vid_mouse_b1 = state; - break; - case SDL_BUTTON_MIDDLE: - vid_mouse_b2 = state; - break; - case SDL_BUTTON_RIGHT: - vid_mouse_b3 = state; - break; - } if (SDL_SemWait (vid_mouse_events.sem) == 0) { + switch (event->button) { + case SDL_BUTTON_LEFT: + vid_mouse_b1 = state; + break; + case SDL_BUTTON_MIDDLE: + vid_mouse_b2 = state; + break; + case SDL_BUTTON_RIGHT: + vid_mouse_b3 = state; + break; + } sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event: State: %d, Button: %d, (%d,%d)\n", event->state, event->button, event->x, event->y); if (vid_mouse_events.count < MAX_EVENTS) { ev.x_rel = 0; @@ -1400,9 +921,11 @@ if (SDL_SemWait (vid_mouse_events.sem) == 0) { if (vid_mouse_events.tail == MAX_EVENTS) vid_mouse_events.tail = 0; } - if (SDL_SemPost (vid_mouse_events.sem)) { - sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event: SDL_SemPost error: %s\n", SDL_GetError()); + else { + sim_debug (SIM_VID_DBG_MOUSE, vid_dev, "Mouse Button Event Discarded: Count: %d\n", vid_mouse_events.count); } + if (SDL_SemPost (vid_mouse_events.sem)) + sim_printf ("%s: Mouse Button Event: SDL_SemPost error: %s\n", sim_dname(vid_dev), SDL_GetError()); } } @@ -1418,23 +941,99 @@ vid_dst.h = vid_height; sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Video Update Event: \n"); if (sim_deb) fflush (sim_deb); -if (SDL_RenderClear (vid_renderer)) { - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Video Update Event: SDL_RenderClear error: %s\n", SDL_GetError()); - } -if (SDL_RenderCopy (vid_renderer, vid_texture, NULL, NULL)) { - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Video Update Event: SDL_RenderCopy error: %s\n", SDL_GetError()); - } +#if SDL_MAJOR_VERSION == 1 +SDL_BlitSurface (vid_image, NULL, vid_window, &vid_dst); +SDL_UpdateRects (vid_window, 1, &vid_dst); +#else +if (SDL_RenderClear (vid_renderer)) + sim_printf ("%s: Video Update Event: SDL_RenderClear error: %s\n", sim_dname(vid_dev), SDL_GetError()); +if (SDL_RenderCopy (vid_renderer, vid_texture, NULL, NULL)) + sim_printf ("%s: Video Update Event: SDL_RenderCopy error: %s\n", sim_dname(vid_dev), SDL_GetError()); SDL_RenderPresent (vid_renderer); +#endif +} + +void vid_update_cursor (SDL_Cursor *cursor, t_bool visible) +{ +if (!cursor) + return; +sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Cursor Update Event: Previously %s, Now %s, New Cursor object at: %p, Old Cursor object at: %p\n", + SDL_ShowCursor(-1) ? "visible" : "invisible", visible ? "visible" : "invisible", cursor, vid_cursor); +SDL_SetCursor (cursor); +#if SDL_MAJOR_VERSION == 1 +if (visible) + SDL_WarpMouse (vid_cursor_x, vid_cursor_y);/* sync position */ +#else +if ((vid_window == SDL_GetMouseFocus ()) && visible) + SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y);/* sync position */ +#endif +if (vid_cursor) + SDL_FreeCursor (vid_cursor); +vid_cursor = cursor; +SDL_ShowCursor (visible); +vid_cursor_visible = visible; +} + +void vid_warp_position (void) +{ +sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "Mouse Warp Event: Warp to: (%d,%d)\n", vid_cursor_x, vid_cursor_y); + +SDL_PumpEvents (); +#if SDL_MAJOR_VERSION == 1 +SDL_WarpMouse (vid_cursor_x, vid_cursor_y); +#else +SDL_WarpMouseInWindow (NULL, vid_cursor_x, vid_cursor_y); +#endif +SDL_PumpEvents (); } int vid_thread (void* arg) { SDL_Event event; +#if SDL_MAJOR_VERSION == 1 +static char *eventtypes[] = { + "NOEVENT", /**< Unused (do not remove) */ + "ACTIVEEVENT", /**< Application loses/gains visibility */ + "KEYDOWN", /**< Keys pressed */ + "KEYUP", /**< Keys released */ + "MOUSEMOTION", /**< Mouse moved */ + "MOUSEBUTTONDOWN", /**< Mouse button pressed */ + "MOUSEBUTTONUP", /**< Mouse button released */ + "JOYAXISMOTION", /**< Joystick axis motion */ + "JOYBALLMOTION", /**< Joystick trackball motion */ + "JOYHATMOTION", /**< Joystick hat position change */ + "JOYBUTTONDOWN", /**< Joystick button pressed */ + "JOYBUTTONUP", /**< Joystick button released */ + "QUIT", /**< User-requested quit */ + "SYSWMEVENT", /**< System specific event */ + "EVENT_RESERVEDA", /**< Reserved for future use.. */ + "EVENT_RESERVEDB", /**< Reserved for future use.. */ + "VIDEORESIZE", /**< User resized video mode */ + "VIDEOEXPOSE", /**< Screen needs to be redrawn */ + "EVENT_RESERVED2", /**< Reserved for future use.. */ + "EVENT_RESERVED3", /**< Reserved for future use.. */ + "EVENT_RESERVED4", /**< Reserved for future use.. */ + "EVENT_RESERVED5", /**< Reserved for future use.. */ + "EVENT_RESERVED6", /**< Reserved for future use.. */ + "EVENT_RESERVED7", /**< Reserved for future use.. */ + "USEREVENT", /** Events SDL_USEREVENT(24) through SDL_MAXEVENTS-1(31) are for your use */ + "", + "", + "", + "", + "", + "", + "" + }; +#else static char *eventtypes[SDL_LASTEVENT]; +#endif +static char *windoweventtypes[256]; static t_bool initialized = FALSE; if (!initialized) { initialized = TRUE; +#if SDL_MAJOR_VERSION != 1 eventtypes[SDL_QUIT] = "QUIT"; /**< User-requested quit */ /* These application events have special meaning on iOS, see README-ios.txt for details */ @@ -1467,34 +1066,54 @@ if (!initialized) { eventtypes[SDL_WINDOWEVENT] = "WINDOWEVENT"; /**< Window state change */ eventtypes[SDL_SYSWMEVENT] = "SYSWMEVENT"; /**< System specific event */ + windoweventtypes[SDL_WINDOWEVENT_NONE] = "NONE"; /**< Never used */ + windoweventtypes[SDL_WINDOWEVENT_SHOWN] = "SHOWN"; /**< Window has been shown */ + windoweventtypes[SDL_WINDOWEVENT_HIDDEN] = "HIDDEN"; /**< Window has been hidden */ + windoweventtypes[SDL_WINDOWEVENT_EXPOSED] = "EXPOSED"; /**< Window has been exposed and should be + redrawn */ + windoweventtypes[SDL_WINDOWEVENT_MOVED] = "MOVED"; /**< Window has been moved to data1, data2 + */ + windoweventtypes[SDL_WINDOWEVENT_RESIZED] = "RESIZED"; /**< Window has been resized to data1xdata2 */ + windoweventtypes[SDL_WINDOWEVENT_SIZE_CHANGED] = "SIZE_CHANGED";/**< The window size has changed, either as a result of an API call or through the system or user changing the window size. */ + windoweventtypes[SDL_WINDOWEVENT_MINIMIZED] = "MINIMIZED"; /**< Window has been minimized */ + windoweventtypes[SDL_WINDOWEVENT_MAXIMIZED] = "MAXIMIZED"; /**< Window has been maximized */ + windoweventtypes[SDL_WINDOWEVENT_RESTORED] = "RESTORED"; /**< Window has been restored to normal size + and position */ + windoweventtypes[SDL_WINDOWEVENT_ENTER] = "ENTER"; /**< Window has gained mouse focus */ + windoweventtypes[SDL_WINDOWEVENT_LEAVE] = "LEAVE"; /**< Window has lost mouse focus */ + windoweventtypes[SDL_WINDOWEVENT_FOCUS_GAINED] = "FOCUS_GAINED";/**< Window has gained keyboard focus */ + windoweventtypes[SDL_WINDOWEVENT_FOCUS_LOST] = "FOCUS_LOST"; /**< Window has lost keyboard focus */ + windoweventtypes[SDL_WINDOWEVENT_CLOSE] = "CLOSE"; /**< The window manager requests that the + window be closed */ + /* Keyboard events */ - eventtypes[SDL_KEYDOWN] = "KEYDOWN"; /**< Key pressed */ - eventtypes[SDL_KEYUP] = "KEYUP"; /**< Key released */ - eventtypes[SDL_TEXTEDITING] = "TEXTEDITING"; /**< Keyboard text editing (composition) */ - eventtypes[SDL_TEXTINPUT] = "TEXTINPUT"; /**< Keyboard text input */ + eventtypes[SDL_KEYDOWN] = "KEYDOWN"; /**< Key pressed */ + eventtypes[SDL_KEYUP] = "KEYUP"; /**< Key released */ + eventtypes[SDL_TEXTEDITING] = "TEXTEDITING"; /**< Keyboard text editing (composition) */ + eventtypes[SDL_TEXTINPUT] = "TEXTINPUT"; /**< Keyboard text input */ /* Mouse events */ - eventtypes[SDL_MOUSEMOTION] = "MOUSEMOTION"; /**< Mouse moved */ - eventtypes[SDL_MOUSEBUTTONDOWN] = "MOUSEBUTTONDOWN"; /**< Mouse button pressed */ - eventtypes[SDL_MOUSEBUTTONUP] = "MOUSEBUTTONUP"; /**< Mouse button released */ - eventtypes[SDL_MOUSEWHEEL] = "MOUSEWHEEL"; /**< Mouse wheel motion */ + eventtypes[SDL_MOUSEMOTION] = "MOUSEMOTION"; /**< Mouse moved */ + eventtypes[SDL_MOUSEBUTTONDOWN] = "MOUSEBUTTONDOWN"; /**< Mouse button pressed */ + eventtypes[SDL_MOUSEBUTTONUP] = "MOUSEBUTTONUP"; /**< Mouse button released */ + eventtypes[SDL_MOUSEWHEEL] = "MOUSEWHEEL"; /**< Mouse wheel motion */ /* Joystick events */ - eventtypes[SDL_JOYAXISMOTION] = "JOYAXISMOTION"; /**< Joystick axis motion */ - eventtypes[SDL_JOYBALLMOTION] = "JOYBALLMOTION"; /**< Joystick trackball motion */ - eventtypes[SDL_JOYHATMOTION] = "JOYHATMOTION"; /**< Joystick hat position change */ - eventtypes[SDL_JOYBUTTONDOWN] = "JOYBUTTONDOWN"; /**< Joystick button pressed */ - eventtypes[SDL_JOYBUTTONUP] = "JOYBUTTONUP"; /**< Joystick button released */ - eventtypes[SDL_JOYDEVICEADDED] = "JOYDEVICEADDED"; /**< A new joystick has been inserted into the system */ - eventtypes[SDL_JOYDEVICEREMOVED] = "JOYDEVICEREMOVED"; /**< An opened joystick has been removed */ + eventtypes[SDL_JOYAXISMOTION] = "JOYAXISMOTION"; /**< Joystick axis motion */ + eventtypes[SDL_JOYBALLMOTION] = "JOYBALLMOTION"; /**< Joystick trackball motion */ + eventtypes[SDL_JOYHATMOTION] = "JOYHATMOTION"; /**< Joystick hat position change */ + eventtypes[SDL_JOYBUTTONDOWN] = "JOYBUTTONDOWN"; /**< Joystick button pressed */ + eventtypes[SDL_JOYBUTTONUP] = "JOYBUTTONUP"; /**< Joystick button released */ + eventtypes[SDL_JOYDEVICEADDED] = "JOYDEVICEADDED"; /**< A new joystick has been inserted into the system */ + eventtypes[SDL_JOYDEVICEREMOVED] = "JOYDEVICEREMOVED"; /**< An opened joystick has been removed */ /* Game controller events */ - eventtypes[SDL_CONTROLLERAXISMOTION] = "CONTROLLERAXISMOTION"; /**< Game controller axis motion */ + eventtypes[SDL_CONTROLLERAXISMOTION] = "CONTROLLERAXISMOTION"; /**< Game controller axis motion */ eventtypes[SDL_CONTROLLERBUTTONDOWN] = "CONTROLLERBUTTONDOWN"; /**< Game controller button pressed */ - eventtypes[SDL_CONTROLLERBUTTONUP] = "CONTROLLERBUTTONUP"; /**< Game controller button released */ - eventtypes[SDL_CONTROLLERDEVICEADDED] = "CONTROLLERDEVICEADDED"; /**< A new Game controller has been inserted into the system */ - eventtypes[SDL_CONTROLLERDEVICEREMOVED] = "CONTROLLERDEVICEREMOVED"; /**< An opened Game controller has been removed */ - eventtypes[SDL_CONTROLLERDEVICEREMAPPED] = "CONTROLLERDEVICEREMAPPED"; /**< The controller mapping was updated */ + eventtypes[SDL_CONTROLLERBUTTONUP] = "CONTROLLERBUTTONUP"; /**< Game controller button released */ + eventtypes[SDL_CONTROLLERDEVICEADDED] = "CONTROLLERDEVICEADDED"; /**< A new Game controller has been inserted into the system */ + eventtypes[SDL_CONTROLLERDEVICEREMOVED] = "CONTROLLERDEVICEREMOVED"; /**< An opened Game controller has been removed */ + eventtypes[SDL_CONTROLLERDEVICEREMAPPED] = "CONTROLLERDEVICEREMAPPED"; /**< The controller mapping was updated */ /* Touch events */ eventtypes[SDL_FINGERDOWN] = "FINGERDOWN"; @@ -1512,27 +1131,45 @@ if (!initialized) { /* Drag and drop events */ eventtypes[SDL_DROPFILE] = "DROPFILE"; /**< The system requests a file open */ +#if (SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL >= 3) /* Render events */ -#if defined(SDL_RENDER_TARGETS_RESET) eventtypes[SDL_RENDER_TARGETS_RESET] = "RENDER_TARGETS_RESET"; /**< The render targets have been reset */ #endif -#if defined(SDL_RENDER_DEVICE_RESET) - eventtypes[SDL_RENDER_DEVICE_RESET] = "SDL_RENDER_DEVICE_RESET"; /**< The render device has been reset */ + +#if (SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL >= 4) + /* Render events */ + eventtypes[SDL_RENDER_DEVICE_RESET] = "RENDER_DEVICE_RESET"; /**< The render device has been reset */ #endif + /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use, * and should be allocated with SDL_RegisterEvents() */ eventtypes[SDL_USEREVENT] = "USEREVENT"; - +#endif /* SDL_MAJOR_VERSION != 1 */ } sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Starting\n"); -vid_mono_palette[0] = sim_end ? 0xFF000000 : 0x000000FF; -vid_mono_palette[1] = 0xFFFFFFFF; +vid_mono_palette[0] = sim_end ? 0xFF000000 : 0x000000FF; /* Black */ +vid_mono_palette[1] = 0xFFFFFFFF; /* White */ memset (&vid_key_state, 0, sizeof(vid_key_state)); +#if SDL_MAJOR_VERSION == 1 +SDL_Init (SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE); + +vid_window = SDL_SetVideoMode (vid_width, vid_height, 8, 0); + +SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + +if (sim_end) + vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); +else + vid_image = SDL_CreateRGBSurface (SDL_SWSURFACE, vid_width, vid_height, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); + +#else +SDL_SetHint (SDL_HINT_RENDER_DRIVER, "software"); + SDL_Init (SDL_INIT_VIDEO); SDL_CreateWindowAndRenderer (vid_width, vid_height, SDL_WINDOW_SHOWN, &vid_window, &vid_renderer); @@ -1543,7 +1180,6 @@ if ((vid_window == NULL) || (vid_renderer == NULL)) { return 0; } -SDL_SetWindowTitle (vid_window, sim_name); SDL_SetRenderDrawColor (vid_renderer, 0, 0, 0, 255); SDL_RenderClear (vid_renderer); SDL_RenderPresent (vid_renderer); @@ -1564,7 +1200,33 @@ if (!vid_texture) { SDL_StopTextInput (); -sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Started\n"); +vid_windowID = SDL_GetWindowID (vid_window); + +#endif + +if (vid_flags & SIM_VID_INPUTCAPTURED) { + char title[150]; + + memset (title, 0, sizeof(title)); + strncpy (title, sim_name, sizeof(title)-1); + strncat (title, " ReleaseKey=", sizeof(title)-(1+strlen(title))); + strncat (title, vid_release_key, sizeof(title)-(1+strlen(title))); +#if SDL_MAJOR_VERSION == 1 + SDL_WM_SetCaption (title, title); +#else + SDL_SetWindowTitle (vid_window, title); +#endif + } +else +#if SDL_MAJOR_VERSION == 1 + SDL_WM_SetCaption (sim_name, sim_name); +#else + SDL_SetWindowTitle (vid_window, sim_name); +#endif + +vid_ready = TRUE; + +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Started\n"); while (vid_active) { int status = SDL_WaitEvent (&event); @@ -1584,44 +1246,85 @@ while (vid_active) { case SDL_MOUSEMOTION: vid_mouse_move ((SDL_MouseMotionEvent*)&event); break; - +#if SDL_MAJOR_VERSION != 1 + case SDL_WINDOWEVENT: + if (event.window.windowID == vid_windowID) { + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Window Event: %d - %s\n", event.window.event, windoweventtypes[event.window.event]); + switch (event.window.event) { + case SDL_WINDOWEVENT_ENTER: + if (vid_flags & SIM_VID_INPUTCAPTURED) + SDL_WarpMouseInWindow (NULL, vid_width/2, vid_height/2); /* center position */ + break; + } + } + break; +#endif case SDL_USEREVENT: - /* There are 2 user events generated */ + /* There are 4 user events generated */ /* EVENT_REDRAW to update the display */ + /* EVENT_CURSOR to change the current cursor */ + /* EVENT_WARP to warp the cursor position */ /* EVENT_CLOSE to wake up this thread and let */ /* it notice vid_active has changed */ - if (event.user.code == EVENT_REDRAW) { - SDL_Event dummy_event; - - vid_update (); - /* Only do a single video update between waiting for events */ - while (SDL_PeepEvents (&dummy_event, 1, SDL_GETEVENT, SDL_USEREVENT, SDL_USEREVENT)) { - sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_thread() - Ignored extra REDRAW Event\n"); + while (event.user.code) { + if (event.user.code == EVENT_REDRAW) { + vid_update (); + event.user.code = 0; /* Mark as done */ +#if SDL_MAJOR_VERSION == 1 +if (0) while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_USEREVENT))) { +#else +if (0) while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SDL_USEREVENT, SDL_USEREVENT)) { +#endif + if (event.user.code == EVENT_REDRAW) { + /* Only do a single video update between waiting for events */ + sim_debug (SIM_VID_DBG_VIDEO, vid_dev, "vid_thread() - Ignored extra REDRAW Event\n"); + event.user.code = 0; /* Mark as done */ + continue; + } + break; + } + } + if (event.user.code == EVENT_CURSOR) { + vid_update_cursor ((SDL_Cursor *)(event.user.data1), (t_bool)((size_t)event.user.data2)); + event.user.data1 = NULL; + event.user.code = 0; /* Mark as done */ + } + if (event.user.code == EVENT_WARP) { + vid_warp_position (); + event.user.code = 0; /* Mark as done */ + } + if (event.user.code == EVENT_CLOSE) { + event.user.code = 0; /* Mark as done */ } } break; default: - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Ignored Event: Type: %s(%d)\n", eventtypes[event.type], event.type); + sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Ignored Event: Type: %s(%d)\n", eventtypes[event.type], event.type); break; } } - else - if (status < 0) { - sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - SDL_WaitEvent error: %s\n", SDL_GetError()); - } + else { + if (status < 0) + sim_printf ("%s: vid_thread() - SDL_WaitEvent error: %s\n", sim_dname(vid_dev), SDL_GetError()); + } } +if (vid_cursor) { + SDL_FreeCursor (vid_cursor); + vid_cursor = NULL; + } +#if SDL_MAJOR_VERSION != 1 SDL_DestroyTexture(vid_texture); vid_texture = NULL; SDL_DestroyRenderer(vid_renderer); vid_renderer = NULL; SDL_DestroyWindow(vid_window); +#endif /* SDL_MAJOR_VERSION != 1 */ vid_window = NULL; SDL_Quit (); -sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_thread() - Exiting\n"); +sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE|SIM_VID_DBG_CURSOR, vid_dev, "vid_thread() - Exiting\n"); return 0; } -#endif /* libSDL2 implementation */ const char *vid_version(void) { @@ -1657,7 +1360,186 @@ return SCPE_NOFNC; t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, void* desc) { -fprintf (st, "ReleaseKey=Ctrl-Right-Shift"); +if (vid_flags & SIM_VID_INPUTCAPTURED) + fprintf (st, "ReleaseKey=%s", vid_release_key); +return SCPE_OK; +} + +t_stat vid_show_video (FILE* st, UNIT* uptr, int32 val, void* desc) +{ +int i; + +fprintf (st, "Video support using SDL: %s\n", vid_version()); +if (!vid_active) + SDL_Init(SDL_INIT_VIDEO); +else { + fprintf (st, " Currently Active Video Window: (%d by %d pixels)\n", vid_width, vid_height); + fprintf (st, " "); + vid_show_release_key (st, uptr, val, desc); + fprintf (st, "\n"); +#if SDL_MAJOR_VERSION != 1 + fprintf (st, " SDL Video Driver: %s\n", SDL_GetCurrentVideoDriver()); +#endif + } +#if SDL_MAJOR_VERSION == 1 +if (1) { + char driver_name[64]; + const SDL_VideoInfo *info = SDL_GetVideoInfo(); + + fprintf (st, " Video Driver: %s\n", SDL_VideoDriverName(driver_name, sizeof(driver_name))); + fprintf (st, " hardware surfaces available: %s\n", info->hw_available ? "Yes" : "No"); + fprintf (st, " window manager available: %s\n", info->wm_available ? "Yes" : "No"); + fprintf (st, " hardware to hardware blits accelerated: %s\n", info->blit_hw ? "Yes" : "No"); + fprintf (st, " hardware to hardware colorkey blits accelerated: %s\n", info->blit_hw_CC ? "Yes" : "No"); + fprintf (st, " hardware to hardware alpha blits accelerated: %s\n", info->blit_hw_A ? "Yes" : "No"); + fprintf (st, " software to hardware blits accelerated: %s\n", info->blit_sw ? "Yes" : "No"); + fprintf (st, " software to hardware colorkey blits accelerated: %s\n", info->blit_sw_CC ? "Yes" : "No"); + fprintf (st, " software to hardware alpha blits accelerated: %s\n", info->blit_sw_A ? "Yes" : "No"); + fprintf (st, " color fills accelerated: %s\n", info->blit_fill ? "Yes" : "No"); + fprintf (st, " Video Memory: %dKb\n", info->video_mem); + } +#else +for (i = 0; i < SDL_GetNumVideoDisplays(); ++i) { + SDL_DisplayMode display; + + if (SDL_GetCurrentDisplayMode(i, &display)) { + fprintf (st, "Could not get display mode for video display #%d: %s", i, SDL_GetError()); + } + else { + fprintf (st, " Display %s(#%d): current display mode is %dx%dpx @ %dhz. \n", SDL_GetDisplayName(i), i, display.w, display.h, display.refresh_rate); + } + } +fprintf (st, " Available SDL Renderers:\n"); +for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { + SDL_RendererInfo info; + + if (SDL_GetRenderDriverInfo (i, &info)) { + fprintf (st, "Could not get render driver info for driver #%d: %s", i, SDL_GetError()); + } + else { + uint32 j, k; + static struct {uint32 format; char *name;} PixelFormats[] = { + {SDL_PIXELFORMAT_INDEX1LSB, "Index1LSB"}, + {SDL_PIXELFORMAT_INDEX1MSB, "Index1MSB"}, + {SDL_PIXELFORMAT_INDEX4LSB, "Index4LSB"}, + {SDL_PIXELFORMAT_INDEX4MSB, "Index4MSB"}, + {SDL_PIXELFORMAT_INDEX8, "Index8"}, + {SDL_PIXELFORMAT_RGB332, "RGB332"}, + {SDL_PIXELFORMAT_RGB444, "RGB444"}, + {SDL_PIXELFORMAT_RGB555, "RGB555"}, + {SDL_PIXELFORMAT_BGR555, "BGR555"}, + {SDL_PIXELFORMAT_ARGB4444, "ARGB4444"}, + {SDL_PIXELFORMAT_RGBA4444, "RGBA4444"}, + {SDL_PIXELFORMAT_ABGR4444, "ABGR4444"}, + {SDL_PIXELFORMAT_BGRA4444, "BGRA4444"}, + {SDL_PIXELFORMAT_ARGB1555, "ARGB1555"}, + {SDL_PIXELFORMAT_RGBA5551, "RGBA5551"}, + {SDL_PIXELFORMAT_ABGR1555, "ABGR1555"}, + {SDL_PIXELFORMAT_BGRA5551, "BGRA5551"}, + {SDL_PIXELFORMAT_RGB565, "RGB565"}, + {SDL_PIXELFORMAT_BGR565, "BGR565"}, + {SDL_PIXELFORMAT_RGB24, "RGB24"}, + {SDL_PIXELFORMAT_BGR24, "BGR24"}, + {SDL_PIXELFORMAT_RGB888, "RGB888"}, + {SDL_PIXELFORMAT_RGBX8888, "RGBX8888"}, + {SDL_PIXELFORMAT_BGR888, "BGR888"}, + {SDL_PIXELFORMAT_BGRX8888, "BGRX8888"}, + {SDL_PIXELFORMAT_ARGB8888, "ARGB8888"}, + {SDL_PIXELFORMAT_RGBA8888, "RGBA8888"}, + {SDL_PIXELFORMAT_ABGR8888, "ABGR8888"}, + {SDL_PIXELFORMAT_BGRA8888, "BGRA8888"}, + {SDL_PIXELFORMAT_ARGB2101010, "ARGB2101010"}, + {SDL_PIXELFORMAT_YV12, "YV12"}, + {SDL_PIXELFORMAT_IYUV, "IYUV"}, + {SDL_PIXELFORMAT_YUY2, "YUY2"}, + {SDL_PIXELFORMAT_UYVY, "UYVY"}, + {SDL_PIXELFORMAT_YVYU, "YVYU"}, + {SDL_PIXELFORMAT_UNKNOWN, "Unknown"}}; + + fprintf (st, " Render #%d - %s\n", i, info.name); + fprintf (st, " Flags: 0x%X - ", info.flags); + if (info.flags & SDL_RENDERER_SOFTWARE) + fprintf (st, "Software|"); + if (info.flags & SDL_RENDERER_ACCELERATED) + fprintf (st, "Accelerated|"); + if (info.flags & SDL_RENDERER_PRESENTVSYNC) + fprintf (st, "PresentVSync|"); + if (info.flags & SDL_RENDERER_TARGETTEXTURE) + fprintf (st, "TargetTexture|"); + fprintf (st, "\n"); + if ((info.max_texture_height != 0) || (info.max_texture_width != 0)) + fprintf (st, " Max Texture: %d by %d\n", info.max_texture_height, info.max_texture_width); + fprintf (st, " Pixel Formats:\n"); + for (j=0; j