Newer
Older
#include <stdio.h> /* NULL */
#include <string.h>
#include "gen_defs.h"
#include "genwrap.h"
#include "dirwrap.h"
#include "xpbeep.h"
#include <xp_dl.h>
#if (defined CIOLIB_IMPORTS)
#undef CIOLIB_IMPORTS
#endif
#if (defined CIOLIB_EXPORTS)
#undef CIOLIB_EXPORTS
#endif
#include "ciolib.h"
#include "utf8_codepages.h"
#include "vidmodes.h"
#define BITMAP_CIOLIB_DRIVER
#include "SDL.h"
int bitmap_width,bitmap_height;
/* 256 bytes so I can cheat */
unsigned char sdl_keybuf[256]; /* Keyboard buffer */
unsigned char sdl_key=0; /* Index into keybuf for next key in buffer */
unsigned char sdl_keynext=0; /* Index into keybuf for next free position */
bool internal_scaling = true; // Protected by the win mutex
SDL_Renderer *renderer=NULL;
SDL_Texture *texture=NULL;
pthread_mutex_t win_mutex;
sem_t sdl_ufunc_ret;
sem_t sdl_ufunc_rec;
pthread_mutex_t sdl_ufunc_mtx;
sem_t sdl_flush_sem;
pthread_mutex_t sdl_keylock;
sem_t sdl_key_pending;
struct sdl_keyvals {
int keysym
,key
,shift
,ctrl
,alt;
};
static pthread_mutex_t sdl_headlock;
static struct rectlist *update_list = NULL;
static struct rectlist *update_list_tail = NULL;
SDL_USEREVENT_FLUSH
,SDL_USEREVENT_SETTITLE
,SDL_USEREVENT_SETNAME
,SDL_USEREVENT_SETVIDMODE
,SDL_USEREVENT_SHOWMOUSE
,SDL_USEREVENT_HIDEMOUSE
,SDL_USEREVENT_GETWINPOS
};
const struct sdl_keyvals sdl_keyval[] =
{
{SDLK_BACKSPACE, 0x08, 0x08, 0x7f, 0x0e00},
{SDLK_TAB, 0x09, 0x0f00, 0x9400, 0xa500},
{SDLK_RETURN, 0x0d, 0x0d, 0x0a, 0xa600},
{SDLK_ESCAPE, 0x1b, 0x1b, 0x1b, 0x0100},
{SDLK_SPACE, 0x20, 0x20, 0x0300, 0x20},
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
{SDLK_0, '0', ')', 0, 0x8100},
{SDLK_1, '1', '!', 0, 0x7800},
{SDLK_2, '2', '@', 0x0300, 0x7900},
{SDLK_3, '3', '#', 0, 0x7a00},
{SDLK_4, '4', '$', 0, 0x7b00},
{SDLK_5, '5', '%', 0, 0x7c00},
{SDLK_6, '6', '^', 0x1e, 0x7d00},
{SDLK_7, '7', '&', 0, 0x7e00},
{SDLK_8, '8', '*', 0, 0x7f00},
{SDLK_9, '9', '(', 0, 0x8000},
{SDLK_a, 'a', 'A', 0x01, 0x1e00},
{SDLK_b, 'b', 'B', 0x02, 0x3000},
{SDLK_c, 'c', 'C', 0x03, 0x2e00},
{SDLK_d, 'd', 'D', 0x04, 0x2000},
{SDLK_e, 'e', 'E', 0x05, 0x1200},
{SDLK_f, 'f', 'F', 0x06, 0x2100},
{SDLK_g, 'g', 'G', 0x07, 0x2200},
{SDLK_h, 'h', 'H', 0x08, 0x2300},
{SDLK_i, 'i', 'I', 0x09, 0x1700},
{SDLK_j, 'j', 'J', 0x0a, 0x2400},
{SDLK_k, 'k', 'K', 0x0b, 0x2500},
{SDLK_l, 'l', 'L', 0x0c, 0x2600},
{SDLK_m, 'm', 'M', 0x0d, 0x3200},
{SDLK_n, 'n', 'N', 0x0e, 0x3100},
{SDLK_o, 'o', 'O', 0x0f, 0x1800},
{SDLK_p, 'p', 'P', 0x10, 0x1900},
{SDLK_q, 'q', 'Q', 0x11, 0x1000},
{SDLK_r, 'r', 'R', 0x12, 0x1300},
{SDLK_s, 's', 'S', 0x13, 0x1f00},
{SDLK_t, 't', 'T', 0x14, 0x1400},
{SDLK_u, 'u', 'U', 0x15, 0x1600},
{SDLK_v, 'v', 'V', 0x16, 0x2f00},
{SDLK_w, 'w', 'W', 0x17, 0x1100},
{SDLK_x, 'x', 'X', 0x18, 0x2d00},
{SDLK_y, 'y', 'Y', 0x19, 0x1500},
{SDLK_z, 'z', 'Z', 0x1a, 0x2c00},
{SDLK_PAGEUP, 0x4900, 0x4900, 0x8400, 0x9900},
{SDLK_PAGEDOWN, 0x5100, 0x5100, 0x7600, 0xa100},
{SDLK_END, 0x4f00, 0x4f00, 0x7500, 0x9f00},
{SDLK_HOME, 0x4700, 0x4700, 0x7700, 0x9700},
{SDLK_LEFT, 0x4b00, 0x4b00, 0x7300, 0x9b00},
{SDLK_UP, 0x4800, 0x4800, 0x8d00, 0x9800},
{SDLK_RIGHT, 0x4d00, 0x4d00, 0x7400, 0x9d00},
{SDLK_DOWN, 0x5000, 0x5000, 0x9100, 0xa000},
{SDLK_INSERT, CIO_KEY_IC, CIO_KEY_SHIFT_IC, CIO_KEY_CTRL_IC, CIO_KEY_ALT_IC},
{SDLK_DELETE, CIO_KEY_DC, CIO_KEY_SHIFT_DC, CIO_KEY_CTRL_DC, CIO_KEY_ALT_DC},
{SDLK_KP_0, 0x5200, 0x5200, 0x9200, 0},
{SDLK_KP_1, 0x4f00, 0x4f00, 0x7500, 0},
{SDLK_KP_2, 0x5000, 0x5000, 0x9100, 0},
{SDLK_KP_3, 0x5100, 0x5100, 0x7600, 0},
{SDLK_KP_4, 0x4b00, 0x4b00, 0x7300, 0},
{SDLK_KP_5, 0x4c00, 0x4c00, 0x8f00, 0},
{SDLK_KP_6, 0x4d00, 0x4d00, 0x7400, 0},
{SDLK_KP_7, 0x4700, 0x4700, 0x7700, 0},
{SDLK_KP_8, 0x4800, 0x4800, 0x8d00, 0},
{SDLK_KP_9, 0x4900, 0x4900, 0x8400, 0},
{SDLK_KP_MULTIPLY, '*', '*', 0x9600, 0x3700},
{SDLK_KP_PLUS, '+', '+', 0x9000, 0x4e00},
{SDLK_KP_MINUS, '-', '-', 0x8e00, 0x4a00},
{SDLK_KP_PERIOD, 0x7f, 0x7f, 0x5300, 0x9300},
{SDLK_KP_DIVIDE, '/', '/', 0x9500, 0xa400},
{SDLK_KP_ENTER, 0x0d, 0x0d, 0x0a, 0xa600},
{SDLK_F1, 0x3b00, 0x5400, 0x5e00, 0x6800},
{SDLK_F2, 0x3c00, 0x5500, 0x5f00, 0x6900},
{SDLK_F3, 0x3d00, 0x5600, 0x6000, 0x6a00},
{SDLK_F4, 0x3e00, 0x5700, 0x6100, 0x6b00},
{SDLK_F5, 0x3f00, 0x5800, 0x6200, 0x6c00},
{SDLK_F6, 0x4000, 0x5900, 0x6300, 0x6d00},
{SDLK_F7, 0x4100, 0x5a00, 0x6400, 0x6e00},
{SDLK_F8, 0x4200, 0x5b00, 0x6500, 0x6f00},
{SDLK_F9, 0x4300, 0x5c00, 0x6600, 0x7000},
{SDLK_F10, 0x4400, 0x5d00, 0x6700, 0x7100},
{SDLK_F11, 0x8500, 0x8700, 0x8900, 0x8b00},
{SDLK_F12, 0x8600, 0x8800, 0x8a00, 0x8c00},
{SDLK_BACKSLASH, '\\', '|', 0x1c, 0x2b00},
{SDLK_SLASH, '/', '?', 0, 0x3500},
{SDLK_MINUS, '-', '_', 0x1f, 0x8200},
{SDLK_EQUALS, '=', '+', 0, 0x8300},
{SDLK_LEFTBRACKET, '[', '{', 0x1b, 0x1a00},
{SDLK_RIGHTBRACKET, ']', '}', 0x1d, 0x1b00},
{SDLK_SEMICOLON, ';', ':', 0, 0x2700},
{SDLK_QUOTE, '\'', '"', 0, 0x2800},
{SDLK_COMMA, ',', '<', 0, 0x3300},
{SDLK_PERIOD, '.', '>', 0, 0x3400},
{SDLK_BACKQUOTE, '`', '~', 0, 0x2900},
{0, 0, 0, 0, 0} /** END **/
};
static void setup_surfaces_locked(struct video_stats *vs);
{
va_list argptr;
ev.type=SDL_USEREVENT;
ev.user.data1=NULL;
ev.user.data2=NULL;
ev.user.code=func;
pthread_mutex_lock(&sdl_ufunc_mtx);
switch(func) {
case SDL_USEREVENT_SETICON:
ev.user.data1=va_arg(argptr, void *);
if((ev.user.data2=(unsigned long *)malloc(sizeof(unsigned long)))==NULL) {
pthread_mutex_unlock(&sdl_ufunc_mtx);
va_end(argptr);
return;
}
*(unsigned long *)ev.user.data2=va_arg(argptr, unsigned long);
break;
case SDL_USEREVENT_SETNAME:
case SDL_USEREVENT_SETTITLE:
if((ev.user.data1=strdup(va_arg(argptr, char *)))==NULL) {
pthread_mutex_unlock(&sdl_ufunc_mtx);
va_end(argptr);
return;
}
break;
case SDL_USEREVENT_MOUSEPOINTER:
ev.user.data1 = (void *)(intptr_t)va_arg(argptr, int);
break;
case SDL_USEREVENT_SHOWMOUSE:
case SDL_USEREVENT_HIDEMOUSE:
case SDL_USEREVENT_FLUSH:
break;
default:
while((rv = sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT))!=1)
YIELD();
break;
}
pthread_mutex_unlock(&sdl_ufunc_mtx);
/* Called from main thread only */
va_list argptr;
SDL_Event ev;
ev.type=SDL_USEREVENT;
ev.user.data1=NULL;
ev.user.data2=NULL;
ev.user.code=func;
va_start(argptr, func);
pthread_mutex_lock(&sdl_ufunc_mtx);
/* Drain the swamp */
while(1) {
switch(func) {
case SDL_USEREVENT_SETVIDMODE:
ev.user.data1 = NULL + va_arg(argptr, int);
ev.user.data2 = NULL + va_arg(argptr, int);
while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)!=1)
YIELD();
break;
case SDL_USEREVENT_GETWINPOS:
ev.user.data1 = va_arg(argptr, void *);
ev.user.data2 = va_arg(argptr, void *);
// Fallthrough
case SDL_USEREVENT_INIT:
case SDL_USEREVENT_QUIT:
while(sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)!=1)
YIELD();
break;
pthread_mutex_unlock(&sdl_ufunc_mtx);
rv = sem_wait(&sdl_ufunc_ret);
if(rv==0)
pthread_mutex_unlock(&sdl_ufunc_mtx);
va_end(argptr);
return(sdl_ufunc_retval);
}
void exit_sdl_con(void)
// Avoid calling exit(0) from an atexit() function...
ciolib_reaper = 0;
sdl_user_func_ret(SDL_USEREVENT_QUIT);
void sdl_copytext(const char *text, size_t buflen)
{
}
char *sdl_getcliptext(void)
{
uint8_t *u8;
u8 = (uint8_t *)sdl.GetClipboardText();
sdl.free(u8);
return ret;
void sdl_drawrect(struct rectlist *data)
data->next = NULL;
pthread_mutex_lock(&sdl_headlock);
if (update_list == NULL)
update_list = update_list_tail = data;
else {
update_list_tail->next = data;
update_list_tail = data;
pthread_mutex_unlock(&sdl_headlock);
sdl_user_func(SDL_USEREVENT_FLUSH);
/*
* Returns true if the specified width/height can use the
* internal scaler
*
* vstat lock must be held
*/
static bool
window_can_scale_internally(struct video_stats *vs)
int ww = vs->winwidth;
int wh = vs->winheight;
aspect_fix(&ww, &wh, vs->aspect_width, vs->aspect_height);
fw = ww;
fh = wh;
aspect_reverse(&ww, &wh, vs->scrnwidth, vs->scrnheight, vs->aspect_width, vs->aspect_height);
if (fw == ww || fh == wh)
internal_scaling_factors(int *x, int *y, struct video_stats *vs)
calc_scaling_factors(x, y, vs->winwidth, vs->winheight, vs->aspect_width, vs->aspect_height, vs->scrnwidth, vs->scrnheight);
int oldcols;
if (mode != CIOLIB_MODE_CUSTOM) {
pthread_mutex_lock(&vstatlock);
if (mode == vstat.mode) {
pthread_mutex_unlock(&vstatlock);
return 0;
}
pthread_mutex_unlock(&vstatlock);
}
sdl_user_func(SDL_USEREVENT_FLUSH);
bitmap_drv_init_mode(mode, &bitmap_width, &bitmap_height);
if (vstat.scrnwidth > 0) {
for (scaling = 1; (scaling + 1) * vstat.scrnwidth < vstat.winwidth; scaling++)
;
}
vstat.winwidth = vstat.scrnwidth * scaling;
vstat.winheight = vstat.scrnheight * scaling;
aspect_fix(&vstat.winwidth, &vstat.winheight, vstat.aspect_width, vstat.aspect_height);
if (oldcols == 0) {
if (ciolib_initial_window_width > 0)
vstat.winwidth = ciolib_initial_window_width;
if (ciolib_initial_window_height > 0)
vstat.winheight = ciolib_initial_window_height;
if (vstat.cols == 40)
oldcols = 40;
}
if (oldcols == 40) {
vstat.winheight /= 2;
}
if (vstat.cols == 40) {
vstat.winheight *= 2;
}
if (vstat.winwidth < vstat.scrnwidth)
vstat.winwidth = vstat.scrnwidth;
if (vstat.winheight < vstat.scrnheight)
vstat.winheight = vstat.scrnheight;
internal_scaling = window_can_scale_internally(&vstat);
pthread_mutex_lock(&sdl_mode_mutex);
sdl_mode = true;
pthread_mutex_unlock(&sdl_mode_mutex);
pthread_mutex_unlock(&vstatlock);
sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE, vstat.winwidth, vstat.winheight);
return(0);
/* Called from main thread only (Passes Event) */
bitmap_drv_init(sdl_drawrect, sdl_flush);
if(mode==CIOLIB_MODE_SDL_FULLSCREEN)
fullscreen=1;
// Needs to be *after* bitmap_drv_init()
sem_post(&startsdl_sem);
sdl_user_func_ret(SDL_USEREVENT_INIT);
if(sdl_init_good) {
cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
FreeConsole();
cio_api.options |= CONIO_OPT_PALETTE_SETTING | CONIO_OPT_SET_TITLE | CONIO_OPT_SET_NAME | CONIO_OPT_SET_ICON;
ciolib_reaper = 0;
sdl_user_func_ret(SDL_USEREVENT_QUIT);
static void
update_cvstat(struct video_stats *vs)
{
if (vs != NULL && vs != &vstat) {
pthread_mutex_lock(&vstatlock);
*vs = vstat;
pthread_mutex_unlock(&vstatlock);
}
}
static void internal_setwinsize(struct video_stats *vs, bool force)
bool changed = true;
w = vs->winwidth;
h = vs->winheight;
if (w > 16384)
w = 16384;
if (h > 16384)
h = 16384;
if (w < vs->scrnwidth)
w = vs->scrnwidth;
if (h < vs->scrnheight)
h = vs->scrnheight;
pthread_mutex_lock(&vstatlock);
if (w == vstat.winwidth && h == vstat.winheight)
changed = force;
else {
vs->winwidth = vstat.winwidth = w;
vs->winheight = vstat.winheight = h;
}
if (!changed) {
pthread_mutex_lock(&win_mutex);
sdl.GetWindowSize(win, &w, &h);
pthread_mutex_unlock(&win_mutex);
if (w != vs->winwidth || h != vs->winheight)
changed = true;
}
pthread_mutex_unlock(&vstatlock);
internal_scaling = window_can_scale_internally(vs);
if (changed)
setup_surfaces_locked(vs);
sdl_user_func_ret(SDL_USEREVENT_SETVIDMODE, w, h);
pthread_mutex_lock(&win_mutex);
pthread_mutex_unlock(&win_mutex);
}
void sdl_getwinsize_locked(int *w, int *h)
{
if (w)
}
void sdl_getwinsize(int *w, int *h)
{
pthread_mutex_lock(&vstatlock);
sdl_getwinsize_locked(w, h);
pthread_mutex_unlock(&vstatlock);
/* Called from main thread only */
int sdl_kbhit(void)
{
int ret;
pthread_mutex_lock(&sdl_keylock);
ret=(sdl_key!=sdl_keynext);
pthread_mutex_unlock(&sdl_keylock);
return(ret);
}
/* Called from main thread only */
int sdl_getch(void)
{
int ch;
sem_wait(&sdl_key_pending);
pthread_mutex_lock(&sdl_keylock);
/* This always frees up space in keybuf for one more char */
ch=sdl_keybuf[sdl_key++];
/* If we have missed mouse keys, tack them on to the end of the buffer now */
if(sdl_pending_mousekeys) {
if(sdl_pending_mousekeys & 1) /* Odd number... second char */
sdl_keybuf[sdl_keynext++]=CIO_KEY_MOUSE >> 8;
else /* Even number... first char */
sdl_keybuf[sdl_keynext++]=CIO_KEY_MOUSE & 0xff;
sem_post(&sdl_key_pending);
sdl_pending_mousekeys--;
}
pthread_mutex_unlock(&sdl_keylock);
return(ch);
}
/* Called from main thread only */
void sdl_textmode(int mode)
{
sdl_init_mode(mode);
}
/* Called from main thread only (Passes Event) */
int sdl_setname(const char *name)
{
sdl_user_func(SDL_USEREVENT_SETNAME,name);
return(0);
}
/* Called from main thread only (Passes Event) */
int sdl_seticon(const void *icon, unsigned long size)
{
sdl_user_func(SDL_USEREVENT_SETICON,icon,size);
return(0);
}
/* Called from main thread only (Passes Event) */
int sdl_settitle(const char *title)
{
sdl_user_func(SDL_USEREVENT_SETTITLE,title);
return(0);
}
int sdl_showmouse(void)
{
sdl_user_func(SDL_USEREVENT_SHOWMOUSE);
return(1);
}
int sdl_hidemouse(void)
{
sdl_user_func(SDL_USEREVENT_HIDEMOUSE);
int sdl_get_window_info(int *width, int *height, int *xpos, int *ypos)
{
if (xpos || ypos) {
sdl_user_func_ret(SDL_USEREVENT_GETWINPOS, &wx, &wy);
if(xpos)
*xpos=wx;
if(ypos)
*ypos=wy;
}
if (width || height) {
pthread_mutex_lock(&vstatlock);
if(width)
if(height)
pthread_mutex_unlock(&vstatlock);
}
return(1);
static void setup_surfaces_locked(struct video_stats *vs)
SDL_Texture *newtexture;
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
flags |= SDL_WINDOW_RESIZABLE;
#if (SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL >= 1)
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
#endif
pthread_mutex_lock(&win_mutex);
idealmw = vs->scrnwidth;
idealmh = vs->scrnheight;
aspect_correct(&idealmw, &idealmh, vs->aspect_width, vs->aspect_height);
idealw = vs->winwidth;
idealh = vs->winheight;
internal_scaling = window_can_scale_internally(vs);
sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, internal_scaling ? "0" : "2");
if (win == NULL) {
// SDL2: This is slow sometimes... not sure why.
if (sdl.CreateWindowAndRenderer(vs->winwidth, vs->winheight, flags, &win, &renderer) == 0) {
vs->winwidth = idealw;
vs->winheight = idealh;
sdl.RenderClear(renderer);
if (internal_scaling)
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, idealw, idealh);
else
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, vs->scrnwidth, vs->scrnheight);
sdl.DestroyTexture(texture);
texture = newtexture;
}
else {
win = NULL;
renderer = NULL;
sdl.SetWindowMinimumSize(win, idealmw, idealmh);
sdl.SetWindowSize(win, idealw, idealh);
vs->winwidth = idealw;
vs->winheight = idealh;
if (internal_scaling)
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, idealw, idealh);
else
newtexture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, vs->scrnwidth, vs->scrnheight);
sdl.RenderClear(renderer);
if (texture)
sdl.DestroyTexture(texture);
texture = newtexture;
if (vs != &vstat) {
pthread_mutex_lock(&vstatlock);
vstat.winwidth = vs->winwidth;
vstat.winheight = vs->winheight;
sdl.SetWindowMinimumSize(win, idealmw, idealmh);
bitmap_drv_request_pixels();
}
else if(sdl_init_good) {
ev.type=SDL_QUIT;
sdl_exitcode=1;
sdl.PeepEvents(&ev, 1, SDL_ADDEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
pthread_mutex_unlock(&win_mutex);
/* Called from event thread only */
static void sdl_add_key(unsigned int keyval, struct video_stats *vs)
fullscreen=!fullscreen;
cio_api.mode=fullscreen?CIOLIB_MODE_SDL_FULLSCREEN:CIOLIB_MODE_SDL;
sdl.SetWindowFullscreen(win, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
return;
}
if(keyval <= 0xffff) {
pthread_mutex_lock(&sdl_keylock);
if(sdl_keynext+1==sdl_key) {
pthread_mutex_unlock(&sdl_keylock);
return;
}
if((sdl_keynext+2==sdl_key) && keyval > 0xff) {
if(keyval==CIO_KEY_MOUSE)
sdl_pending_mousekeys+=2;
else
pthread_mutex_unlock(&sdl_keylock);
return;
}
sdl_keybuf[sdl_keynext++]=keyval & 0xff;
sem_post(&sdl_key_pending);
if(keyval>0xff) {
sdl_keybuf[sdl_keynext++]=keyval >> 8;
sem_post(&sdl_key_pending);
pthread_mutex_unlock(&sdl_keylock);
}
}
static void
sdl_add_key_uc(unsigned int keyval, struct video_stats *vs)
{
if (keyval < 128)
keyval = cpchar_from_unicode_cpoint(getcodepage(), keyval, keyval);
sdl_add_key(keyval, vs);
}
/* Called from event thread only */
static unsigned int sdl_get_char_code(unsigned int keysym, unsigned int mod)
/* We don't handle META */
if (mod & KMOD_GUI)
return(0x0001ffff);
/* Glah! */
if(keysym==0x7f && !(mod & KMOD_CTRL)) {
keysym=0x08;
/* Find the SDL keysym */
for(i=0;sdl_keyval[i].keysym;i++) {
if(sdl_keyval[i].keysym==keysym) {
/* KeySym found in table */
/*
* Using the modifiers, look up the expected scan code.
*/
if(mod & KMOD_ALT)
expect = sdl_keyval[i].alt;
else if(mod & KMOD_CTRL)
expect=sdl_keyval[i].ctrl;
else if(mod & KMOD_SHIFT) {
if((mod & KMOD_CAPS) && keysym != '\t')
expect=sdl_keyval[i].key;
else
expect=sdl_keyval[i].shift;
}
else {
if(mod & KMOD_CAPS && (toupper(sdl_keyval[i].key) == sdl_keyval[i].shift))
expect=sdl_keyval[i].shift;
else
expect=sdl_keyval[i].key;
}
return(expect);
* Well, we can't find it in our table, or it's a regular key.
if(keysym > 0 && keysym < 128) {
if (isalpha(keysym)) {
/*
* If CAPS and SHIFT are not in the same state,
* upper-case.
*/
if(!!(mod & KMOD_CAPS) != !!(mod & KMOD_SHIFT))
return toupper(keysym);
}
return keysym;
}
/* Give up. It's not working out for us. */
return(0x0001ffff);
static void
sdl_add_keys(uint8_t *utf8s, struct video_stats *vs)
{
char *chars;
char *p;
chars = utf8_to_cp(getcodepage(), utf8s, '\x00', strlen((char *)utf8s), NULL);
if (chars) {
for (p = chars; *p; p++) {
}
free(chars);
}
}
/* Mouse event/keyboard thread */
while(1) {
if(mouse_wait())
static int win_to_text_xpos(int winpos, struct video_stats *vs)
int ret;
ret = winpos/(((float)vs->winwidth)/vs->cols)+1;
if (ret > vs->cols)
ret = vs->cols;
static int win_to_text_ypos(int winpos, struct video_stats *vs)
int ret;
ret = winpos/(((float)vs->winheight)/vs->rows)+1;
if (ret > vs->rows)
ret = vs->rows;
static int win_to_res_xpos(int winpos, struct video_stats *vs)
{
int ret;
ret = winpos * (vs->scrnwidth) / vs->winwidth;
return ret;
}
static int win_to_res_ypos(int winpos, struct video_stats *vs)
{
int ret;
ret = winpos * (vs->scrnheight) / vs->winheight;
return ret;
}
{
SDL_Event ev;
int block_text = 0;
static SDL_Keycode last_sym = SDLK_UNKNOWN;
static Uint16 last_mod = 0;
struct video_stats cvstat = vstat;
if(sdl.WaitEventTimeout(&ev, 1)!=1)
continue;
switch (ev.type) {
case SDL_KEYDOWN: /* Keypress */
last_mod = ev.key.keysym.mod;
last_sym = ev.key.keysym.sym;
if ((ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)) && !(ev.key.keysym.mod & KMOD_MODE)) {
block_text = 1;
if ((ev.key.keysym.mod & KMOD_ALT) &&
(ev.key.keysym.sym == SDLK_LEFT ||
int w, h;
// Don't allow ALT-DIR to change size when maximized...
if ((sdl.GetWindowFlags(win) & SDL_WINDOW_MAXIMIZED) == 0) {
update_cvstat(&cvstat);
w = cvstat.winwidth;
h = cvstat.winheight;
aspect_fix(&w, &h, cvstat.aspect_width, cvstat.aspect_height);
if (cvstat.aspect_width == 0 || cvstat.aspect_height == 0)
wc = true;
else
wc = lround((double)(h * cvstat.aspect_width) / cvstat.aspect_height * cvstat.scrnwidth / cvstat.scrnheight) > w;
switch(ev.key.keysym.sym) {
case SDLK_LEFT:
if (wc) {
if (w % (cvstat.scrnwidth)) {
w = w - w % cvstat.scrnwidth;
}
else {
w -= cvstat.scrnwidth;
if (w < cvstat.scrnwidth)
w = cvstat.scrnwidth;
}
if (h % (cvstat.scrnheight)) {
h = h - h % cvstat.scrnheight;
}
else {
h -= cvstat.scrnheight;
if (h < cvstat.scrnheight)
h = cvstat.scrnheight;
}
if (wc)
w = (w - w % cvstat.scrnwidth) + cvstat.scrnwidth;
else
h = (h - h % cvstat.scrnheight) + cvstat.scrnheight;
if (wc)
h = INT_MAX;
else
w = INT_MAX;
aspect_fix(&w, &h, cvstat.aspect_width, cvstat.aspect_height);
if (w > 16384 || h > 16384)
beep();
else {
cvstat.winwidth = w;
cvstat.winheight = h;
internal_scaling = window_can_scale_internally(&cvstat);
}
if (ev.key.keysym.mod & KMOD_RALT) { // Possible AltGr, let textinput sort it out...
block_text = 0;
}
if ((ev.key.keysym.mod & KMOD_SHIFT) && (ev.key.keysym.sym == '\t'))
block_text = 1;
if (block_text || ev.key.keysym.sym < 0 || ev.key.keysym.sym > 127) {
// NUMLOCK makes
if ((ev.key.keysym.mod & KMOD_NUM) && ((ev.key.keysym.sym >= SDLK_KP_1 && ev.key.keysym.sym <= SDLK_KP_0)
|| ev.key.keysym.sym == SDLK_KP_DIVIDE
|| ev.key.keysym.sym == SDLK_KP_MULTIPLY
|| ev.key.keysym.sym == SDLK_KP_MINUS
|| ev.key.keysym.sym == SDLK_KP_PLUS
|| ev.key.keysym.sym == SDLK_KP_PERIOD))
break;
sdl_add_key_uc(sdl_get_char_code(ev.key.keysym.sym, ev.key.keysym.mod), &cvstat);
}
else if (!isprint(ev.key.keysym.sym)) {
if (ev.key.keysym.sym < 128)
sdl_add_key_uc(ev.key.keysym.sym, &cvstat);
}
break;
case SDL_TEXTINPUT:
if (!block_text) {
unsigned int charcode = sdl_get_char_code(last_sym, last_mod & ~(KMOD_ALT));
// If the key is exactly what we would expect, use sdl_get_char_code()
if (*(uint8_t *)ev.text.text == charcode)
sdl_add_key_uc(sdl_get_char_code(last_sym, last_mod), &cvstat);
sdl_add_keys((uint8_t *)ev.text.text, &cvstat);
}
break;
case SDL_KEYUP:
last_mod = ev.key.keysym.mod;
if (!(ev.key.keysym.mod & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)))
block_text = 0;
break;
case SDL_MOUSEMOTION:
pthread_once(&ciolib_mouse_initialized, init_mouse);
ciomouse_gotevent(CIOLIB_MOUSE_MOVE,win_to_text_xpos(ev.motion.x, &cvstat),win_to_text_ypos(ev.motion.y, &cvstat), win_to_res_xpos(ev.motion.x, &cvstat), win_to_res_ypos(ev.motion.y, &cvstat));
pthread_once(&ciolib_mouse_initialized, init_mouse);
switch(ev.button.button) {
case SDL_BUTTON_LEFT:
ciomouse_gotevent(CIOLIB_BUTTON_PRESS(1),win_to_text_xpos(ev.button.x, &cvstat),win_to_text_ypos(ev.button.y, &cvstat), win_to_res_xpos(ev.button.x, &cvstat), win_to_res_ypos(ev.button.y, &cvstat));