shithub: npe

ref: 0d98a32151079982dd23af0f3eca91b971eb1d6b
dir: /libnpe_sdl2/events.c/

View raw version
#include "_sdl.h"

enum {
	/* FIXME missing plumber→dropfile */
	Ckey,
	Ckeytype,
	Cmouse,
	Cresize,
	Numchan,

	Rdown = 0,
	Rup,
	Rrepeat,
};

static int kmod;
static Rune rune;
static Keyboardctl kctl;
static int quitreq;

static Alt salt[Numchan+1] = {
	[Ckey] = { nil, &rune, CHANRCV },
	[Ckeytype] = { nil, nil, CHANNOP },
	[Cmouse] = { nil, &npe_sdl.m, CHANRCV },
	[Cresize] = { nil, nil, CHANRCV },
	[Numchan] = { nil, nil, CHANNOBLK },
};

static void kbdproc(void *);
static void mouseproc(void *);

int
npe_sdl_init_input(void)
{
	if((npe_sdl.mctl = initmouse(nil, screen)) == nil)
		return -1;

	salt[Ckey].c = chancreate(sizeof(Rune), 20);
	salt[Ckeytype].c = chancreate(sizeof(int), 20);
	salt[Cmouse].c = chancreate(sizeof(Mouse), 20);
	salt[Cresize].c = npe_sdl.mctl->resizec;
	kctl.c = salt[Ckey].c; /* for enter() */

	if(salt[Ckey].c == nil || salt[Ckeytype].c == nil || salt[Cmouse].c == nil)
		return -1;

	if(proccreate(kbdproc, nil, 4096) < 0 || proccreate(mouseproc, nil, 4096) < 0)
		return -1;

	return 0;
}

Uint32
SDL_GetWindowID(SDL_Window *win)
{
	USED(win);
	return 1;
}

SDL_Keymod
SDL_GetModState(void)
{
	return kmod;
}

int
SDL_EventState(Uint32, int)
{
	return 0;
}

int
SDL_RegisterEvents(int)
{
	/* FIXME this will need implementation if SDL_PushEvent is */
	return -1;
}

int
SDL_PushEvent(SDL_Event *event)
{
	/* FIXME does it matter? */
	USED(event);
	return -1;
}

int
SDL_QuitRequested(void)
{
	return quitreq;
}

struct {
	SDL_EventFilter f;
	void *aux;
} filter = {
	nil,
	nil,
};

void
SDL_SetEventFilter(SDL_EventFilter f, void *userdata)
{
	filter.f = f;
	filter.aux = userdata;
}

void
SDL_PumpEvents(void)
{
	/* FIXME does it matter? */
}

#define ISTEXT(r) ((r) >= 0x20 && ((r) < KF || (r) >= KF+0x1000))

int
SDL_PollEvent(SDL_Event *e)
{
	int t, down;

	if(e == nil) /* FIXME need to buffer the event so it won't get lost */
		return 0;

	switch(alt(salt)){
	case Ckey:
		memset(e, 0, sizeof(*e));
		recv(salt[Ckeytype].c, &t);
		if(npe_sdl.textinput && ISTEXT(rune)){
			if(t == Rup)
				break;
			e->type = SDL_TEXTINPUT;
			e->text.text[runetochar(e->text.text, &rune)] = 0;
			goto Filter;
		}else if((npe_sdl.hints & Altf4noclose) == 0 && (kmod & KMOD_LALT) != 0 && rune == (KF|4)){
			e->type = SDL_QUIT;
			quitreq = 1;
			goto Filter;
		}else{
			e->type = (t == Rup) ? SDL_KEYUP : SDL_KEYDOWN;
			e->key.repeat = t == Rrepeat;
			e->key.keysym.scancode = SDL_GetScancodeFromKey(rune);
			if(rune == '\n')
				rune = SDLK_RETURN;
			e->key.keysym.sym = rune;
			e->key.state = e->type;
			goto Filter;
		}
		break;

	case Cmouse:
		if(screen == nil)
			break;

		if(eqpt(npe_sdl.m.xy, Pt(-1, -1))){
			npe_sdl.m.xy = npe_sdl.center;
			npe_sdl.om.xy = npe_sdl.center;
			return 0; /* swallow */
		}

		memset(e, 0, sizeof(*e));
		e->motion.x = (npe_sdl.m.xy.x - screen->r.min.x) * npe_sdl.scale;
		e->motion.y = (npe_sdl.m.xy.y - screen->r.min.y) * npe_sdl.scale;
		e->motion.xrel = (npe_sdl.m.xy.x - npe_sdl.om.xy.x) * npe_sdl.scale;
		e->motion.yrel = (npe_sdl.m.xy.y - npe_sdl.om.xy.y) * npe_sdl.scale;

		if(!eqpt(npe_sdl.m.xy, npe_sdl.om.xy)){
			npe_sdl.mredraw = 1;
			if(npe_sdl.m.buttons == npe_sdl.om.buttons){
				e->type = SDL_MOUSEMOTION;
				e->motion.state = npe_sdl.m.buttons;
				goto Filter;
			}
		}
		if(npe_sdl.m.buttons == npe_sdl.om.buttons)
			break;
		/* FIXME there is a lot of hope for multiple buttons to never change its state at the same time */
		if((down = (npe_sdl.m.buttons & 1)) != (npe_sdl.om.buttons & 1)){ /* left */
			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
			e->button.button = SDL_BUTTON_LEFT;
			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~1) | (npe_sdl.m.buttons & 1);
			goto Filter;
		}
		if((down = (npe_sdl.m.buttons & 2)) != (npe_sdl.om.buttons & 2)){ /* middle */
			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
			e->button.button = SDL_BUTTON_MIDDLE;
			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~2) | (npe_sdl.m.buttons & 2);
			goto Filter;
		}
		if((down = (npe_sdl.m.buttons & 4)) != (npe_sdl.om.buttons & 4)){ /* right */
			e->type = down ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
			e->button.button = SDL_BUTTON_RIGHT;
			npe_sdl.om.buttons = (npe_sdl.om.buttons & ~4) | (npe_sdl.m.buttons & 4);
			goto Filter;
		}
		if(npe_sdl.m.buttons & (8|16)){
			e->type = SDL_MOUSEWHEEL;
			e->wheel.x = 0;
			e->wheel.y = (npe_sdl.m.buttons & 8) ? 1 : -1;
			goto Filter;
		}
		break;

	case Cresize:
		memset(e, 0, sizeof(*e));
		npe_sdl.fullredraw = 1;
		while(getwindow(display, Refnone) != 1)
			;
		e->type = SDL_WINDOWEVENT;
		e->window.event = SDL_WINDOWEVENT_EXPOSED;
		e->window.windowID = 1; //TODO more then one?
		goto Filter;
	}

	return 0;

Filter:
	if(filter.f != nil && filter.f(filter.aux, e) == 0)
		return 0;
	return 1;
}

int
SDL_WaitEvent(SDL_Event *e)
{
	int r;

	salt[Numchan].op = CHANEND;
	r = SDL_PollEvent(e);
	salt[Numchan].op = CHANNOBLK;

	return r;
}

SDL_Scancode
SDL_GetScancodeFromKey(SDL_Keycode r)
{
	if(r >= 'a' && r <= 'z')
		return r - 'a' + SDL_SCANCODE_A;
	if(r >= '1' && r <= '9')
		return r - '1' + SDL_SCANCODE_1;
	if(r == '0')  return SDL_SCANCODE_0;
	if(r == '\n') return SDL_SCANCODE_RETURN;
	if(r == Kesc) return SDL_SCANCODE_ESCAPE;
	if(r == Kbs)  return SDL_SCANCODE_BACKSPACE;
	if(r == '\t') return SDL_SCANCODE_TAB;
	if(r == ' ')  return SDL_SCANCODE_SPACE;
	if(r == '-')  return SDL_SCANCODE_MINUS;
	if(r == '=')  return SDL_SCANCODE_EQUALS;
	if(r == '[')  return SDL_SCANCODE_LEFTBRACKET;
	if(r == ']')  return SDL_SCANCODE_RIGHTBRACKET;
	if(r == '\\') return SDL_SCANCODE_BACKSLASH;
	if(r == ';')  return SDL_SCANCODE_SEMICOLON;
	if(r == '\'') return SDL_SCANCODE_APOSTROPHE;
	if(r == '/')  return SDL_SCANCODE_SLASH;

	if(r == Kright) return SDL_SCANCODE_RIGHT;
	if(r == Kleft) return SDL_SCANCODE_LEFT;
	if(r == Kdown) return SDL_SCANCODE_DOWN;
	if(r == Kup) return SDL_SCANCODE_UP;
	if(r == Kins) return SDL_SCANCODE_INSERT;
	if(r == Khome) return SDL_SCANCODE_HOME;
	if(r == Kpgup) return SDL_SCANCODE_PAGEUP;
	if(r == Kdel) return SDL_SCANCODE_DELETE;
	if(r == Kend) return SDL_SCANCODE_END;
	if(r == Kpgdown) return SDL_SCANCODE_PAGEDOWN;
	if(r == Kctl) return SDL_SCANCODE_LCTRL;
	if(r == Kshift) return SDL_SCANCODE_LSHIFT;
	if(r == Kalt) return SDL_SCANCODE_LALT;
	if(r == Kmod4) return SDL_SCANCODE_LGUI;
	if(r == Kaltgr) return SDL_SCANCODE_RALT;

	if(r >= (KF|1) && r <= (KF|12)) return SDL_SCANCODE_F1 + r - (KF|1);

/* FIXME
	SDL_SCANCODE_PRINTSCREEN = 0x46,
	SDL_SCANCODE_SCROLLLOCK,
	SDL_SCANCODE_NUMLOCKCLEAR,
	SDL_SCANCODE_KP_DIVIDE,
	SDL_SCANCODE_KP_MULTIPLY,
	SDL_SCANCODE_KP_MINUS,
	SDL_SCANCODE_KP_PLUS,
	SDL_SCANCODE_KP_ENTER,
	SDL_SCANCODE_KP_1,
	SDL_SCANCODE_KP_2,
	SDL_SCANCODE_KP_3,
	SDL_SCANCODE_KP_4,
	SDL_SCANCODE_KP_5,
	SDL_SCANCODE_KP_6,
	SDL_SCANCODE_KP_7,
	SDL_SCANCODE_KP_8,
	SDL_SCANCODE_KP_9,
	SDL_SCANCODE_KP_0,
	SDL_SCANCODE_KP_PERIOD,
	SDL_SCANCODE_NONUSBACKSLASH,
	SDL_SCANCODE_NONUSHASH,
*/
	/* FIXME there are some missing */

	if(r == L'`' || r == L'´') /* FIXME this is most likely wrong */
		return SDL_SCANCODE_GRAVE;

	return r;
}

static Uint8 kbdstate[SDL_NUM_SCANCODES];

Uint8*
SDL_GetKeyboardState(int *numkeys)
{
	if(numkeys != nil)
		*numkeys = SDL_NUM_SCANCODES;
	return kbdstate;
}

char*
SDL_GetKeyName(SDL_Keycode key)
{
	USED(key);
	return ""; /* FIXME */
}

static void
kbdproc(void *)
{
	char buf[128], buf2[128], *s;
	int kfd, n, kbin, t;
	Rune r, scan, o;

	threadsetname("kbdproc");
	if((kfd = open("/dev/kbd", OREAD|OCEXEC)) < 0)
		sysfatal("/dev/kbd: %r");
	kbin = open("/dev/kbin", OWRITE|OCEXEC);

	buf2[0] = 0;
	buf2[1] = 0;
	buf[0] = 0;
	kmod = 0;
	for(;;){
		if(buf[0] != 0){
			n = strlen(buf)+1;
			memmove(buf, buf+n, sizeof(buf)-n);
		}
		if(buf[0] == 0){
			n = read(kfd, buf, sizeof(buf)-1);
			if(n <= 0)
				break;
			buf[n-1] = 0;
			buf[n] = 0;
		}

		switch(buf[0]){
		case 'c':
			if(chartorune(&r, buf+1) > 0 && r != Runeerror){
				if(ISTEXT(r))
					o = r;
				send(salt[Ckey].c, &o);
				send(salt[Ckeytype].c, &t);
				t = Rrepeat;
			}
		default:
			continue;

		case 'k':
			s = buf+1;
			memset(kbdstate, 0, sizeof kbdstate);
			while(*s){
				s += chartorune(&r, s);
				scan = SDL_GetScancodeFromKey(r);
				if(scan < nelem(kbdstate))
					kbdstate[scan] = 1;
				if(utfrune(buf2+1, r) == nil){
					t = Rdown;
					if(r == Kalt){
						/* magic trick: write Alt scancode to disable the "compose" mode */
						/* FIXME: does this work in both native AND drawterm? */
						write(kbin, "\x46", 1);
						kmod |= KMOD_LALT;
					}else if (r == Kshift)
						kmod |= KMOD_LSHIFT;
					else if(r == Kctl)
						kmod |= KMOD_LCTRL;
					else if(r == Kaltgr)
						kmod |= KMOD_RALT;
					else if(r == Kmod4)
						kmod |= KMOD_LGUI;
					else{
						o = npe_sdl.textinput ? r : tolowerrune(r);
						continue;
					}
					o = r;
					send(salt[Ckey].c, &r);
					send(salt[Ckeytype].c, &t);
					t = Rrepeat;
				}
			}
			break;

		case 'K':
			s = buf2+1;
			memset(kbdstate, 0, sizeof kbdstate);
			while(*s){
				s += chartorune(&r, s);
				scan = SDL_GetScancodeFromKey(r);
				if(scan < nelem(kbdstate))
					kbdstate[scan] = 1;
				if(utfrune(buf+1, r) == nil){
					if(r == Kalt)
						kmod &= ~KMOD_LALT;
					else if(r == Kshift)
						kmod &= ~KMOD_LSHIFT;
					else if(r == Kctl)
						kmod &= ~KMOD_LCTRL;

					t = Rup;
					send(salt[Ckey].c, &r);
					send(salt[Ckeytype].c, &t);
				}
			}
			break;
		}
		strcpy(buf2, buf);
	}

	threadexits(nil);
}

static void
mouseproc(void *)
{
	Mouse m;
	for(;;){
		recv(npe_sdl.mctl->c, &m);
		if(npe_sdl.mgrab == SDL_TRUE){
			if(!ptinrect(m.xy, npe_sdl.grabout)){
				moveto(npe_sdl.mctl, npe_sdl.center);
				m.xy = Pt(-1,-1);
			}
		}
		send(salt[Cmouse].c, &m);
	}
}