Skip to content
Snippets Groups Projects
sdl_con.c 40.6 KiB
Newer Older
		case 0x00a0:
			return(0xff);
	}
	return(0x01ffff);
}

/* Called from event thread only */
static unsigned int sdl_get_char_code(unsigned int keysym, unsigned int mod)
deuce's avatar
deuce committed
	int expect;
	int i;

#ifdef __DARWIN__
	if(keysym==0x7f && !(mod & KMOD_CTRL)) {
		keysym=0x08;
		keysym=SDLK_BACKSPACE;
	/*
	 * No Unicode translation available.
	 * Or there *IS* an SDL keysym.
	 * Or ALT (GUI) pressed
	// SDL2: This needs to be replaced with... betterness.
	if((keysym > SDLK_UNKNOWN) || (mod & (KMOD_GUI|KMOD_ALT))) {
deuce's avatar
deuce committed
		for(i=0;sdl_keyval[i].keysym;i++) {
			if(sdl_keyval[i].keysym==keysym) {
				/*
				 * Using the modifiers, look up the expected scan code.
				 * Under windows, this is what unicode will be set to
				 * if the ALT key is not AltGr
				 */

				if(mod & KMOD_CTRL)
					expect=sdl_keyval[i].ctrl;
				else if(mod & KMOD_SHIFT) {
					if(mod & KMOD_CAPS)
						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;
				}

				/*
				 * Now handle the ALT case so that expect will
				 * be what we expect to return
				 */
				if(mod & (KMOD_GUI|KMOD_ALT)) {
deuce's avatar
deuce committed

					/* Yes, this is a "normal" ALT combo */
					if(keysym==expect || keysym == 0)
deuce's avatar
deuce committed
						return(sdl_keyval[i].alt);

					/* AltGr apparently... translate unicode or give up */
					return(cp437_convert(keysym));
deuce's avatar
deuce committed
				}
deuce's avatar
deuce committed

				/*
				 * If the keysym is a keypad one
				 * AND numlock is locked
				 * AND none of Control, Shift, ALT, or GUI are pressed
				if(keysym >= SDLK_KP_0 && keysym <= SDLK_KP_EQUALS && 
						(!(mod & (KMOD_CTRL|KMOD_SHIFT|KMOD_ALT|KMOD_GUI) ))) {
#if defined(_WIN32)
					/*
					 * Apparently, Win32 SDL doesn't interpret keypad with numlock...
					 * and doesn't know the state of numlock either...
					 * So, do that here. *sigh*
					 */

					mod &= ~KMOD_NUM;	// Ignore "current" mod state
					if (GetKeyState(VK_NUMLOCK) & 1)
						mod |= KMOD_NUM;
#endif
					if (mod & KMOD_NUM) {
						switch(keysym) {
								return('9');
							case SDLK_KP_PERIOD:
								return('.');
							case SDLK_KP_DIVIDE:
								return('/');
							case SDLK_KP_MULTIPLY:
								return('*');
							case SDLK_KP_MINUS:
								return('-');
							case SDLK_KP_PLUS:
								return('+');
							case SDLK_KP_ENTER:
								return('\r');
							case SDLK_KP_EQUALS:
								return('=');
						}
				/*
				 * "Extended" keys are always right since we can't compare to unicode
				 * This does *NOT* mean ALT-x, it means things like F1 and Print Screen
				 */
				if(sdl_keyval[i].key > 255)			/* Extended regular key */
deuce's avatar
deuce committed
					return(expect);
deuce's avatar
deuce committed
				 * If there is no unicode translation available,
				 * we *MUST* use our table since we have
				 * no other data to use.  This is apparently
				 * never true on OS X.
deuce's avatar
deuce committed
					return(expect);
deuce's avatar
deuce committed
				/*
				 * At this point, we no longer have a reason to distrust the
				 * unicode mapping.  If we can coerce it into CP437, we will.
				 * If we can't, just give up.
deuce's avatar
deuce committed
				 */
				return(cp437_convert(expect));
deuce's avatar
deuce committed
	}
	/*
	 * Well, we can't find it in our table...
	 * If there's a unicode character, use that if possible.
	 */
	if(keysym)
		return(cp437_convert(keysym));

	/*
	 * No unicode... perhaps it's ASCII?
	 * Most likely, this would be a strangely
	 * entered control character.
	 *
	 * If *any* modifier key is down though
	 * we're not going to trust the keysym
	 * value since we can't.
	 */
	if(keysym <= 127 && !(mod & (KMOD_GUI|KMOD_ALT|KMOD_CTRL|KMOD_SHIFT)))
		return(keysym);

	/* Give up.  It's not working out for us. */
	return(0x0001ffff);
/* Mouse event/keyboard thread */
deuce's avatar
deuce committed
static void sdl_mouse_thread(void *data)
deuce's avatar
deuce committed
	SetThreadName("SDL Mouse");
	while(1) {
		if(mouse_wait())
			sdl_add_key(CIO_KEY_MOUSE);
	}
}

deuce's avatar
deuce committed
static int win_to_text_xpos(int winpos)
deuce's avatar
deuce committed
{
	ret = winpos/(cvstat.charwidth*cvstat.scaling)+1;
	return ret;
deuce's avatar
deuce committed
static int win_to_text_ypos(int winpos)
deuce's avatar
deuce committed
{
	ret = winpos/(cvstat.charheight*cvstat.scaling*cvstat.vmultiplier)+1;
	return ret;
deuce's avatar
deuce committed
static void sdl_video_event_thread(void *data)
deuce's avatar
deuce committed
	int			new_scaling = -1;
deuce's avatar
deuce committed

	old_scaling = cvstat.scaling;

	char	*driver;
	if((driver = sdl.GetCurrentVideoDriver())!=NULL) {
#if defined(_WIN32)
		if(!strcmp(driver,"directx"))
			sdl_using_directx=TRUE;
		sdl_using_directx=FALSE;
#endif
#if (defined(__MACH__) && defined(__APPLE__))
		if(!strcmp(driver,"Quartz"))
			sdl_using_quartz=TRUE;
		sdl_using_quartz=FALSE;
#endif
#if !defined(NO_X) && defined(__unix__)
		if(!strcmp(driver,"x11"))
			sdl_using_x11=TRUE;
		if(!strcmp(driver,"dga"))
			sdl_using_x11=TRUE;
	while(1) {
		if(sdl.WaitEventTimeout(&ev, 1)!=1) {
			if (new_scaling != -1 || cvstat.scaling != old_scaling) {
				if (new_scaling == -1)
					new_scaling = cvstat.scaling;
				sdl_setscaling(new_scaling);
				new_scaling = -1;
				if(cvstat.scaling < 1)
					sdl_setscaling(1);
				setup_surfaces();
				old_scaling = cvstat.scaling;
deuce's avatar
deuce committed
			}
		}
		else {
			switch (ev.type) {
				case SDL_KEYDOWN:			/* Keypress */
					if ((ev.key.keysym.mod & KMOD_GUI) &&
					    (ev.key.keysym.sym == SDLK_LEFT ||
					     ev.key.keysym.sym == SDLK_RIGHT ||
					     ev.key.keysym.sym == SDLK_UP ||
					     ev.key.keysym.sym == SDLK_DOWN)) {
						int w, h;
						sdl.mutexP(win_mutex);
						sdl.GetWindowSize(win, &w, &h);
						switch(ev.key.keysym.sym) {
							case SDLK_LEFT:
								if (w % (cvstat.charwidth * cvstat.cols)) {
									w = w - w % (cvstat.charwidth * cvstat.cols);
								}
								else {
									w -= (cvstat.charwidth * cvstat.cols);
									if (w < (cvstat.charwidth * cvstat.cols))
										w = cvstat.charwidth * cvstat.cols;
								}
								break;
							case SDLK_RIGHT:
								w = (w - w % (cvstat.charwidth * cvstat.cols)) + (cvstat.charwidth * cvstat.cols);
								break;
							case SDLK_UP:
								if (h % (cvstat.charheight * cvstat.rows * cvstat.vmultiplier)) {
									h = h - h % (cvstat.charheight * cvstat.rows);
								}
								else {
									h -= (cvstat.charheight * cvstat.rows * cvstat.vmultiplier);
									if (h < (cvstat.charheight * cvstat.rows * cvstat.vmultiplier))
										h = cvstat.charheight * cvstat.rows * cvstat.vmultiplier;
								}
								break;
							case SDLK_DOWN:
								h = (h - h % (cvstat.charheight * cvstat.rows * cvstat.vmultiplier)) + (cvstat.charheight * cvstat.rows * cvstat.vmultiplier);
								break;
						}
						sdl.SetWindowSize(win, w, h);
						sdl.mutexP(win_mutex);
					}
					else
						sdl_add_key(sdl_get_char_code(ev.key.keysym.sym, ev.key.keysym.mod));
					break;
				case SDL_KEYUP:				/* Ignored (handled in KEYDOWN event) */
					break;
				case SDL_MOUSEMOTION:
					if(!ciolib_mouse_initialized)
					ciomouse_gotevent(CIOLIB_MOUSE_MOVE,win_to_text_xpos(ev.motion.x),win_to_text_ypos(ev.motion.y));
					break;
				case SDL_MOUSEBUTTONDOWN:
					if(!ciolib_mouse_initialized)
					switch(ev.button.button) {
						case SDL_BUTTON_LEFT:
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(1),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
						case SDL_BUTTON_MIDDLE:
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(2),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
						case SDL_BUTTON_RIGHT:
							ciomouse_gotevent(CIOLIB_BUTTON_PRESS(3),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
					}
					break;
				case SDL_MOUSEBUTTONUP:
					if(!ciolib_mouse_initialized)
deuce's avatar
deuce committed
						break;
					switch(ev.button.button) {
						case SDL_BUTTON_LEFT:
							ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(1),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
							break;
						case SDL_BUTTON_MIDDLE:
							ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(2),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
							break;
						case SDL_BUTTON_RIGHT:
							ciomouse_gotevent(CIOLIB_BUTTON_RELEASE(3),win_to_text_xpos(ev.button.x),win_to_text_ypos(ev.button.y));
							break;
					}
					break;
				case SDL_QUIT:
					/*
					 * SDL2: Do we still need the reaper?
					 * This is what exit()s programs when the
					 * X is hit.
					 */
					if (ciolib_reaper)
						exit(0);
					else
						sdl_add_key(CIO_KEY_QUIT);
					break;
				case SDL_WINDOWEVENT:
					switch(ev.window.event) {
						case SDL_WINDOWEVENT_SIZE_CHANGED:
							// SDL2: User resized window
						case SDL_WINDOWEVENT_RESIZED:
							{
								// SDL2: Something resized window
								const char *newh;
								if(ev.window.data1 > 0 && ev.window.data2 > 0) {
									new_scaling = (int)(ev.window.data1/(cvstat.charwidth*cvstat.cols));
								}
								if ((ev.window.data1 % (cvstat.charwidth * cvstat.cols)) || (ev.window.data2 % (cvstat.charheight * cvstat.rows)))
									newh = "2";
								else
									newh = "0";
								sdl.mutexP(win_mutex);
								if (strcmp(newh, sdl.GetHint(SDL_HINT_RENDER_SCALE_QUALITY))) {
									sdl.SetHint(SDL_HINT_RENDER_SCALE_QUALITY, newh );
									sdl.DestroyTexture(texture);
									texture = sdl.CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, cvstat.charwidth*cvstat.cols, cvstat.charheight*cvstat.rows);
									bitmap_drv_request_pixels();
								}
								sdl.mutexV(win_mutex);
								break;
deuce's avatar
deuce committed
							}
						case SDL_WINDOWEVENT_EXPOSED:
							{
								sdl.RenderCopy(renderer, texture, NULL, NULL);
								sdl.RenderPresent(renderer);
deuce's avatar
deuce committed
							}
							break;
					}
					break;
				case SDL_USEREVENT: {
					struct rectlist *list;
					struct rectlist *old_next;
					/* Tell SDL to do various stuff... */
					if (ev.user.code != SDL_USEREVENT_FLUSH)
						if(sdl_x11available && sdl_using_x11)
							sdl.SemPost(sdl_ufunc_rec);
					switch(ev.user.code) {
						case SDL_USEREVENT_QUIT:
							sdl_ufunc_retval=0;
							sdl.SemPost(sdl_ufunc_ret);
deuce's avatar
deuce committed
							return;
						case SDL_USEREVENT_FLUSH:
							sdl.mutexP(win_mutex);
							if (win != NULL) {
								sdl.mutexP(sdl_headlock);
								list = update_list;
								update_list = update_list_tail = NULL;
								sdl.mutexV(sdl_headlock);
								for (; list; list = old_next) {
									old_next = list->next;
									if (list->next == NULL) {
										sdl.UpdateTexture(texture, NULL, list->data, list->rect.width * sizeof(uint32_t));
										src.x = 0;
										src.y = 0;
										src.w = list->rect.width;
										src.h = list->rect.height;
										sdl.RenderCopy(renderer, texture, &src, NULL);
deuce's avatar
deuce committed
								}
								sdl.RenderPresent(renderer);
							}
							sdl.mutexV(win_mutex);
							break;
						case SDL_USEREVENT_SETNAME:
							sdl.SetWindowTitle(win, (char *)ev.user.data1);
							free(ev.user.data1);
							break;
						case SDL_USEREVENT_SETICON:
							if(sdl_icon != NULL)
								sdl.FreeSurface(sdl_icon);
							sdl_icon=sdl.CreateRGBSurfaceFrom(ev.user.data1
									, *(unsigned long *)ev.user.data2
									, *(unsigned long *)ev.user.data2
									, 32
									, *(unsigned long *)ev.user.data2*4
									, *(DWORD *)"\377\0\0\0"
									, *(DWORD *)"\0\377\0\0"
									, *(DWORD *)"\0\0\377\0"
									, *(DWORD *)"\0\0\0\377"
							);
							sdl.SetWindowIcon(win, sdl_icon);
							free(ev.user.data2);
							break;
						case SDL_USEREVENT_SETTITLE:
							sdl.SetWindowTitle(win, (char *)ev.user.data1);
							free(ev.user.data1);
							break;
						case SDL_USEREVENT_SETVIDMODE:
							new_scaling = -1;
							old_scaling = cvstat.scaling;
							setup_surfaces();
							sdl_ufunc_retval=0;
							sdl.SemPost(sdl_ufunc_ret);
							break;
						case SDL_USEREVENT_HIDEMOUSE:
							sdl.ShowCursor(SDL_DISABLE);
							break;
						case SDL_USEREVENT_SHOWMOUSE:
							sdl.ShowCursor(SDL_ENABLE);
							break;
						case SDL_USEREVENT_INIT:
							if(!sdl_init_good) {
								if(sdl.WasInit(SDL_INIT_VIDEO)==SDL_INIT_VIDEO) {
									sdl.mutexP(win_mutex);
deuce's avatar
deuce committed
									_beginthread(sdl_mouse_thread, 0, NULL);
									sdl_init_good=1;
									sdl.mutexV(win_mutex);
							}
							sdl_ufunc_retval=0;
							sdl.SemPost(sdl_ufunc_ret);
							break;
						case SDL_USEREVENT_COPY:
#if !defined(NO_X) && defined(__unix__) && defined(SDL_VIDEO_DRIVER_X11)
							if(sdl_x11available && sdl_using_x11) {
								SDL_SysWMinfo	wmi;

								SDL_VERSION(&(wmi.version));
								sdl.GetWindowWMInfo(win, &wmi);
								sdl.EventState(SDL_SYSWMEVENT, SDL_ENABLE);
								copy_needs_events = 1;
								sdl_x11.XSetSelectionOwner(wmi.info.x11.display, CONSOLE_CLIPBOARD, wmi.info.x11.window, CurrentTime);
							}
#endif
							break;
						case SDL_USEREVENT_PASTE:
#if !defined(NO_X) && defined(__unix__) && defined(SDL_VIDEO_DRIVER_X11)
							if(sdl_x11available && sdl_using_x11) {
								Window sowner=None;
								SDL_SysWMinfo	wmi;

								SDL_VERSION(&(wmi.version));
								sdl.GetWindowWMInfo(win, &wmi);

								paste_needs_events = 1;
								sdl.EventState(SDL_SYSWMEVENT, SDL_ENABLE);
								sowner=sdl_x11.XGetSelectionOwner(wmi.info.x11.display, CONSOLE_CLIPBOARD);
								if(sowner==wmi.info.x11.window) {
									/* Get your own primary selection */
									if(sdl_copybuf==NULL) {
										FREE_AND_NULL(sdl_pastebuf);
									else
										sdl_pastebuf=(char *)malloc(strlen(sdl_copybuf)+1);
									if(sdl_pastebuf!=NULL)
										strcpy(sdl_pastebuf,sdl_copybuf);
									/* Set paste buffer */
									sdl.SemPost(sdl_pastebuf_set);
									sdl.SemWait(sdl_pastebuf_copied);
									FREE_AND_NULL(sdl_pastebuf);
									paste_needs_events = 0;
									if (!copy_needs_events)
										sdl.EventState(SDL_SYSWMEVENT, SDL_DISABLE);
								else if(sowner!=None) {
									sdl_x11.XConvertSelection(wmi.info.x11.display, CONSOLE_CLIPBOARD, XA_STRING, XA_STRING, wmi.info.x11.window, CurrentTime);
								}
								else {
									/* Set paste buffer */
									FREE_AND_NULL(sdl_pastebuf);
									sdl.SemPost(sdl_pastebuf_set);
									sdl.SemWait(sdl_pastebuf_copied);
									paste_needs_events = 0;
									if (!copy_needs_events)
										sdl.EventState(SDL_SYSWMEVENT, SDL_DISABLE);
deuce's avatar
deuce committed
								}
							break;
					}
					break;
				}
				case SDL_SYSWMEVENT:			/* ToDo... This is where Copy/Paste needs doing */
				// SDL2: There's a better way...
#if !defined(NO_X) && defined(__unix__) && defined(SDL_VIDEO_DRIVER_X11)
					if(sdl_x11available && sdl_using_x11) {
						XEvent *e;
						e=&ev.syswm.msg->msg.x11.event;
						switch(e->type) {
							case SelectionClear: {
									XSelectionClearEvent *req;

									req=&(e->xselectionclear);
									sdl.mutexP(sdl_copybuf_mutex);
									if(req->selection==CONSOLE_CLIPBOARD) {
										FREE_AND_NULL(sdl_copybuf);
									}
									sdl.mutexV(sdl_copybuf_mutex);
									copy_needs_events = 0;
									if (!paste_needs_events)
										sdl.EventState(SDL_SYSWMEVENT, SDL_DISABLE);
									break;
							}
							case SelectionNotify: {
									int format=0;
									unsigned long len, bytes_left, dummy;
									Atom type;
									XSelectionEvent *req;
deuce's avatar
deuce committed
									SDL_SysWMinfo	wmi;
									sdl.GetWindowWMInfo(win, &wmi);
									req=&(e->xselection);
									if(req->requestor!=wmi.info.x11.window)
										break;
									if(req->property) {
										sdl_x11.XGetWindowProperty(wmi.info.x11.display, wmi.info.x11.window, req->property, 0, 0, 0, AnyPropertyType, &type, &format, &len, &bytes_left, (unsigned char **)(&sdl_pastebuf));
										if(bytes_left > 0 && format==8)
											sdl_x11.XGetWindowProperty(wmi.info.x11.display, wmi.info.x11.window, req->property,0,bytes_left,0,AnyPropertyType,&type,&format,&len,&dummy,(unsigned char **)&sdl_pastebuf);
										else {
deuce's avatar
deuce committed
											FREE_AND_NULL(sdl_pastebuf);
										}
									}
									else {
										FREE_AND_NULL(sdl_pastebuf);
									}
deuce's avatar
deuce committed

									/* Set paste buffer */
									sdl.SemPost(sdl_pastebuf_set);
									sdl.SemWait(sdl_pastebuf_copied);
									paste_needs_events = 0;
									if (!copy_needs_events)
										sdl.EventState(SDL_SYSWMEVENT, SDL_DISABLE);
									if(sdl_pastebuf!=NULL) {
										sdl_x11.XFree(sdl_pastebuf);
										sdl_pastebuf=NULL;
									}
									break;
							}
							case SelectionRequest: {
									XSelectionRequestEvent *req;
									XEvent respond;

									req=&(e->xselectionrequest);
									sdl.mutexP(sdl_copybuf_mutex);
									if(sdl_copybuf==NULL) {
										respond.xselection.property=None;
									}
									else {
										if(req->target==XA_STRING) {
											sdl_x11.XChangeProperty(req->display, req->requestor, req->property, XA_STRING, 8, PropModeReplace, (unsigned char *)sdl_copybuf, strlen(sdl_copybuf));
											respond.xselection.property=req->property;
deuce's avatar
deuce committed
										}
											respond.xselection.property=None;
									}
									sdl.mutexV(sdl_copybuf_mutex);
									respond.xselection.type=SelectionNotify;
									respond.xselection.display=req->display;
									respond.xselection.requestor=req->requestor;
									respond.xselection.selection=req->selection;
									respond.xselection.target=req->target;
									respond.xselection.time=req->time;
									sdl_x11.XSendEvent(req->display,req->requestor,0,0,&respond);
									break;
							}
						}	/* switch */
					}	/* usingx11 */
deuce's avatar
deuce committed

				/* Ignore this stuff */
				case SDL_JOYAXISMOTION:
				case SDL_JOYBALLMOTION:
				case SDL_JOYHATMOTION:
				case SDL_JOYBUTTONDOWN:
				case SDL_JOYBUTTONUP:
				default:
					break;
deuce's avatar
deuce committed
	return;
	if(init_sdl_video()) {
		fprintf(stderr,"SDL Video Initialization Failed\n");
	sdl_key_pending=sdl.SDL_CreateSemaphore(0);
	sdl_ufunc_ret=sdl.SDL_CreateSemaphore(0);
	sdl_ufunc_rec=sdl.SDL_CreateSemaphore(0);
	sdl_ufunc_mtx=sdl.SDL_CreateMutex();
	sdl_headlock=sdl.SDL_CreateMutex();
	win_mutex=sdl.SDL_CreateMutex();
	sdl_keylock=sdl.SDL_CreateMutex();
#if !defined(NO_X) && defined(__unix__)
	sdl_pastebuf_set=sdl.SDL_CreateSemaphore(0);
	sdl_pastebuf_copied=sdl.SDL_CreateSemaphore(0);
	sdl_copybuf_mutex=sdl.SDL_CreateMutex();
#endif
	return(sdl_init(mode));
}