示例#1
0
static void inject_scheduled(arcan_evctx* ctx)
{
	if (!playback_in.ptr)
		return;

	static arcan_event next_ev;
	static int32_t tickv = -1; /* -1 if no pending events */

step:
	if (tickv != -1){
		if (tickv <= arcan_frametime()){
			arcan_event_enqueue(ctx, &next_ev);
			tickv = -1;
		}
		else
			return;
	}

	ssize_t rv = unpack_rec_event(&playback_in.ptr[playback_ofs],
		playback_in.sz - playback_ofs, &next_ev, &tickv);

	if (-1 == rv){
		arcan_release_map(playback_in);
		memset(&playback_in, '\0', sizeof(playback_in));
		return;
	}

	playback_ofs += rv;
	goto step;
}
示例#2
0
int arcan_event_tryenqueue(arcan_evctx* ctx, const arcan_event* const src)
{
	if (((*ctx->front + 1) % ctx->eventbuf_sz) == *ctx->back)
		return 0;	

	return arcan_event_enqueue(ctx, src);	
}
示例#3
0
文件: event.c 项目: mewbak/arcan
void drop_joytbl(struct arcan_evctx* ctx)
{
	for(int i=0; i < iodev.n_joy; i++){
		if (!iodev.joys[i].tagged){
			struct arcan_event remev = {
				.category = EVENT_IO,
				.io.kind = EVENT_IO_STATUS,
				.io.devid = iodev.joys[i].devnum,
				.io.devkind = EVENT_IDEVKIND_STATUS,
				.io.input.status.devkind = EVENT_IDEVKIND_GAMEDEV,
				.io.input.status.action = EVENT_IDEV_REMOVED
			};

			snprintf((char*) &remev.io.label, sizeof(remev.io.label) /
				sizeof(remev.io.label[0]), "%s", iodev.joys[i].label);
			arcan_event_enqueue(ctx, &remev);

			free(iodev.joys[i].adata);
			free(iodev.joys[i].hattbls);
		}
		else
			iodev.joys[i].tagged = false;

		free(iodev.joys);
		iodev.joys = NULL;
		iodev.n_joy = 0;
	}
}
示例#4
0
文件: event.c 项目: mewbak/arcan
static inline void process_axismotion(arcan_evctx* ctx,
	const SDL_JoyAxisEvent* const ev)
{
	int devid = ev->which;

	if (!iodev.joys || iodev.joys[devid].axis < ev->axis)
		return;

	struct axis_opts* daxis = &iodev.joys[devid].adata[ev->axis];
	int16_t dstv;

	if (process_axis(ctx, daxis, ev->value, &dstv)){
		arcan_event newevent = {
			.category = EVENT_IO,
			.io.kind = EVENT_IO_AXIS_MOVE,
			.io.devid = iodev.joys[devid].devnum,
			.io.subid = ev->axis,
			.io.datatype = EVENT_IDATATYPE_ANALOG,
			.io.devkind  = EVENT_IDEVKIND_GAMEDEV,
			.io.input.analog.gotrel = false,
			.io.input.analog.nvalues = 1,
			.io.input.analog.axisval[0] = dstv
		};
		arcan_event_enqueue(ctx, &newevent);
	}
}
示例#5
0
文件: event.c 项目: Gu1/arcan
static inline void process_mousemotion(arcan_evctx* ctx,
	int16_t xv, int16_t xrel, int16_t yv, int16_t yrel)	
{
	int16_t dstv, dstv_r;
	arcan_event nev = {
		.label = "MOUSE\0",
		.category = EVENT_IO,
		.kind = EVENT_IO_AXIS_MOVE,
		.data.io.datatype = EVENT_IDATATYPE_ANALOG,
		.data.io.devkind  = EVENT_IDEVKIND_MOUSE,
		.data.io.input.analog.devid  = ARCAN_MOUSEIDBASE,
		.data.io.input.analog.gotrel = true,
		.data.io.input.analog.nvalues = 2
	}; 

	snprintf(nev.label, 
		sizeof(nev.label) - 1, "mouse");

	if (process_axis(ctx, &iodev.mx, xv, &dstv) &&
		process_axis(ctx, &iodev.mx_r, xrel, &dstv_r)){
		nev.data.io.input.analog.subid = 0;
		nev.data.io.input.analog.axisval[0] = dstv;
		nev.data.io.input.analog.axisval[1] = dstv_r;
		arcan_event_enqueue(ctx, &nev);	
	}

	if (process_axis(ctx, &iodev.my, yv, &dstv) &&
		process_axis(ctx, &iodev.my_r, yrel, &dstv_r)){
		nev.data.io.input.analog.subid = 1;
		nev.data.io.input.analog.axisval[0] = dstv;
		nev.data.io.input.analog.axisval[1] = dstv_r;
		arcan_event_enqueue(ctx, &nev);	
	}
}

static void set_analogstate(struct axis_opts* dst,
	int lower_bound, int upper_bound, int deadzone,
	int kernel_size, enum ARCAN_ANALOGFILTER_KIND mode)
{	
	dst->lower = lower_bound;
	dst->upper = upper_bound;
	dst->deadzone = deadzone;
	dst->kernel_sz = kernel_size;
	dst->mode = mode;
	dst->kernel_ofs = 0;
}	
示例#6
0
/*
 * enqueue to current context considering input-masking, unless label is set,
 * assign one based on what kind of event it is This function has a similar
 * prototype to the enqueue defined in the interop.h, but a different
 * implementation to support waking up the child, and that blocking behaviors
 * in the main thread is always forbidden.
 */
int arcan_event_enqueue(arcan_evctx* ctx, const struct arcan_event* const src)
{
/* early-out mask-filter, these are only ever used to silently
 * discard input / output (only operate on head and tail of ringbuffer) */
	if (!src || (src->category & ctx->mask_cat_inp) || (ctx->state_fl & 1) > 0)
		return ARCAN_OK;

/* One big caveat with this approach is the possibility of feedback loop with
 * magnification - forcing us to break ordering by directly feeding drain.
 * Given that we have special treatment for _EXPIRE and similar calls,
 * there shouldn't be any functions that has this behavior. Still, broken
 * ordering is better than running out of space. */

 if (((*ctx->back + 1) % ctx->eventbuf_sz) == *ctx->front){
		if (ctx->drain){
/* very rare / impossible, but safe-guard against future bad code */
			if ((ctx->state_fl & 2) > 0){
				arcan_event ev = *src;
				ctx->drain(&ev, 1);
			}
/* tradeoff, can cascade to embarassing GC pause or video- stall but better
 * than data corruption and unpredictable states -- this can theoretically
 * have us return a broken 'custom' error code from some script */
			else {
				ctx->state_fl |= 2;
					arcan_event_feed(ctx, ctx->drain, NULL);
				ctx->state_fl &= ~2;
			}
		}
		else
			return ARCAN_ERRC_OUT_OF_SPACE;
	}

	if (panic_keysym != -1 && panic_keymod != -1 &&
		src->category == EVENT_IO && src->io.kind == EVENT_IO_BUTTON &&
		src->io.devkind == EVENT_IDEVKIND_KEYBOARD &&
		src->io.input.translated.modifiers == panic_keymod &&
		src->io.input.translated.keysym == panic_keysym
	){
		arcan_event ev = {
			.category = EVENT_SYSTEM,
			.sys.kind = EVENT_SYSTEM_EXIT,
			.sys.errcode = EXIT_SUCCESS
		};

		return arcan_event_enqueue(ctx, &ev);
	}

	if (ctx->local && src->category == EVENT_IO)
			pack_rec_event(src);

	ctx->eventbuf[(*ctx->back) % ctx->eventbuf_sz] = *src;
	*ctx->back = (*ctx->back + 1) % ctx->eventbuf_sz;

	return ARCAN_OK;
}
示例#7
0
void arcan_event_queuetransfer(arcan_evctx* dstqueue, arcan_evctx* srcqueue,
	enum ARCAN_EVENT_CATEGORY allowed, float saturation, arcan_vobj_id source)
{
	if (!srcqueue || !dstqueue || (srcqueue && !srcqueue->front)
		|| (srcqueue && !srcqueue->back))
		return;

	bool wake = false;

	arcan_frameserver* tgt = arcan_video_feedstate(source) ?
		arcan_video_feedstate(source)->ptr : NULL;

	saturation = (saturation > 1.0 ? 1.0 : saturation < 0.5 ? 0.5 : saturation);

	while ( srcqueue->front && *srcqueue->front != *srcqueue->back &&
			floor((float)dstqueue->eventbuf_sz * saturation) > queue_used(dstqueue)) {

		arcan_event inev;
		if (arcan_event_poll(srcqueue, &inev) == 0)
			break;

/*
 * update / translate to make sure the corresponding frameserver<->lua mapping
 * can be found and tracked, there are also a few events that should be handled
 * here rather than propagated (bufferstream for instance).
 */
		if ((inev.category & allowed) == 0 )
			continue;

		if (inev.category == EVENT_EXTERNAL){
			switch(inev.ext.kind){

/* to protect against scripts that would happily try to just allocate/respond
 * to what a the event says, clamp this here */
				case EVENT_EXTERNAL_SEGREQ:
					if (inev.ext.segreq.width > PP_SHMPAGE_MAXW)
						inev.ext.segreq.width = PP_SHMPAGE_MAXW;

					if (inev.ext.segreq.height > PP_SHMPAGE_MAXH)
						inev.ext.segreq.height = PP_SHMPAGE_MAXH;
				break;

				case EVENT_EXTERNAL_BUFFERSTREAM:
/* this assumes that we are in non-blocking state and that a single
 * CSMG on a socket is sufficient for a non-blocking recvmsg */
					if (tgt->vstream.handle)
						close(tgt->vstream.handle);

					tgt->vstream.handle = arcan_fetchhandle(tgt->dpipe, false);
					tgt->vstream.stride = inev.ext.bstream.pitch;
					tgt->vstream.format = inev.ext.bstream.format;
					continue;
				break;

/* for autoclocking, only one-fire events are forwarded if flag has been set */
				case EVENT_EXTERNAL_CLOCKREQ:
					if (tgt->flags.autoclock && !inev.ext.clock.once){
						tgt->clock.frame = inev.ext.clock.dynamic;
						tgt->clock.left = tgt->clock.start = inev.ext.clock.rate;
						continue;
					}
				break;

				case EVENT_EXTERNAL_REGISTER:
					if (tgt->segid == SEGID_UNKNOWN){
/* 0.6/CRYPTO - need actual signature authentication here */
						tgt->guid[0] = inev.ext.registr.guid[0];
						tgt->guid[1] = inev.ext.registr.guid[1];
					}
					snprintf(tgt->title,
						COUNT_OF(tgt->title), "%s", inev.ext.registr.title);
				break;
/* note: one could manually enable EVENT_INPUT and use separate processes
 * as input sources (with all the risks that comes with it security wise)
 * if that ever becomes a concern, here would be a good place to consider
 * filtering the panic_key* */

/* client may need more fine grained control for audio transfers when it
 * comes to synchronized A/V playback */
				case EVENT_EXTERNAL_FLUSHAUD:
					if (tgt)
						arcan_frameserver_flush(tgt);
					continue;
				break;

				default:
				break;
			}
			inev.ext.source = source;
		}

		else if (inev.category == EVENT_NET){
			inev.net.source = source;
		}

		wake = true;

		arcan_event_enqueue(dstqueue, &inev);
	}

	if (wake)
		arcan_sem_post(srcqueue->synch.handle);
}
示例#8
0
文件: event.c 项目: mewbak/arcan
void platform_event_rescan_idev(arcan_evctx* ctx)
{
	if (iodev.sticks_init)
		SDL_QuitSubSystem(SDL_INIT_JOYSTICK);

	SDL_Init(SDL_INIT_JOYSTICK);
	SDL_JoystickEventState(SDL_ENABLE);

	int n_joys = SDL_NumJoysticks();
	iodev.sticks_init = true;

	if (n_joys == 0){
		drop_joytbl(ctx);
		return;
	}

/*
 * (Re) scan/open all joysticks,
 * look for matching / already present devices
 * and copy their settings.
 */
	size_t jsz = sizeof(struct arcan_stick) * n_joys;
	struct arcan_stick* joys = malloc(jsz);
	memset(joys, '\0', jsz);

	for (int i = 0; i < n_joys; i++) {
		struct arcan_stick* dj = &joys[i];
		struct arcan_stick* sj = NULL;
		unsigned long hashid = djb_hash(SDL_JoystickName(i));

/* find existing */
		if (iodev.joys){
			for (int j = 0; j < iodev.n_joy; j++){
				if (iodev.joys[j].hashid == hashid){
					sj = &iodev.joys[j];
					break;
				}
			}

/* if found, copy to new table */
			if (sj){
				memcpy(dj, sj, sizeof(struct arcan_stick));
				if (dj->hats){
					dj->hattbls = malloc(dj->hats * sizeof(unsigned));
					memcpy(dj->hattbls, sj->hattbls, sizeof(unsigned) * sj->hats);
				}

				if (dj->axis){
					dj->adata = malloc(dj->axis * sizeof(struct axis_opts));
					memcpy(dj->adata, sj->adata, sizeof(struct axis_opts) * sj->axis);
				}

				dj->handle = SDL_JoystickOpen(i);
				continue;
			}
		}

/* otherwise add as new entry */
		strncpy(dj->label, SDL_JoystickName(i), 255);
		dj->hashid = djb_hash(SDL_JoystickName(i));
		dj->handle = SDL_JoystickOpen(i);
		dj->devnum = gen_devid(dj->hashid);

		dj->axis    = SDL_JoystickNumAxes(joys[i].handle);
		dj->buttons = SDL_JoystickNumButtons(joys[i].handle);
		dj->balls   = SDL_JoystickNumBalls(joys[i].handle);
		dj->hats    = SDL_JoystickNumHats(joys[i].handle);

		if (dj->hats > 0){
			size_t dst_sz = joys[i].hats * sizeof(unsigned);
			dj->hattbls = malloc(dst_sz);
			memset(joys[i].hattbls, 0, dst_sz);
		}

		if (dj->axis > 0){
			size_t ad_sz = sizeof(struct axis_opts) * dj->axis;
			dj->adata = malloc(ad_sz);
			memset(dj->adata, '\0', ad_sz);
			for (int i = 0; i < dj->axis; i++){
				dj->adata[i].mode = ARCAN_ANALOGFILTER_AVG;
/* these values are sortof set
 * based on the SixAxis (common enough, and noisy enough) */
				dj->adata[i].lower    = -32765;
				dj->adata[i].deadzone = 5000;
				dj->adata[i].upper    = 32768;
				dj->adata[i].kernel_sz = 1;
			}
		}

/* notify the rest of the system about the added device */
		struct arcan_event addev = {
			.category = EVENT_IO,
			.io.kind = EVENT_IO_STATUS,
			.io.devkind = EVENT_IDEVKIND_STATUS,
			.io.devid = dj->devnum,
			.io.input.status.devkind = EVENT_IDEVKIND_GAMEDEV,
			.io.input.status.action = EVENT_IDEV_ADDED
		};
		snprintf((char*) &addev.io.label, sizeof(addev.io.label) /
			sizeof(addev.io.label[0]), "%s", dj->label);
		arcan_event_enqueue(ctx, &addev);
	}

	iodev.n_joy = n_joys;
	iodev.joys = joys;
}

void platform_event_keyrepeat(arcan_evctx* ctx, int* rate, int* delay)
{
/* sdl repeat start disabled */
	static int cur_rep, cur_del;
	bool upd = false;

	if (*rate < 0){
		*rate = cur_rep;
	}
	else{
		int tmp = *rate;
		*rate = cur_rep;
		cur_rep = tmp;
		upd = true;
	}

	if (*delay < 0){
		*delay = cur_del;
	}
	else{
		int tmp = *delay;
		*delay = cur_del;
		cur_del = tmp;
		upd = true;
	}

	if (upd)
		SDL_EnableKeyRepeat(cur_del, cur_rep);
}

void platform_event_deinit(arcan_evctx* ctx)
{
	if (iodev.sticks_init){
		SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
		iodev.sticks_init = false;
	}
}

void platform_event_reset(arcan_evctx* ctx)
{
	platform_event_deinit(ctx);
}
示例#9
0
文件: event.c 项目: mewbak/arcan
static inline void process_hatmotion(arcan_evctx* ctx, unsigned devid,
	unsigned hatid, unsigned value)
{
	if (!iodev.joys)
		return;

	static unsigned hattbl[4] = {SDL_HAT_UP, SDL_HAT_DOWN,
		SDL_HAT_LEFT, SDL_HAT_RIGHT};

	assert(iodev.n_joy > devid);
	assert(iodev.joys[devid].hats > hatid);

	arcan_event newevent = {
		.category = EVENT_IO,
		.io.kind = EVENT_IO_BUTTON,
		.io.datatype = EVENT_IDATATYPE_DIGITAL,
		.io.devkind = EVENT_IDEVKIND_GAMEDEV,
		.io.devid = iodev.joys[devid].devnum,
		.io.subid = 128 + (hatid * 4)
	};

/* shouldn't really ever be the same, but not trusting SDL */
	if (iodev.joys[devid].hattbls[ hatid ] != value){
		unsigned oldtbl = iodev.joys[devid].hattbls[hatid];

		for (int i = 0; i < 4; i++){
			if ( (oldtbl & hattbl[i]) != (value & hattbl[i]) ){
				newevent.io.subid  = (hatid * 4) + i;
				newevent.io.input.digital.active =
					(value & hattbl[i]) > 0;
				arcan_event_enqueue(ctx, &newevent);
			}
		}

		iodev.joys[devid].hattbls[hatid] = value;
	}
}

const char* platform_event_devlabel(int devid)
{
	if (devid == -1)
		return "mouse";

	devid = find_devind(devid);

	if (devid < 0 || devid >= iodev.n_joy)
		return "no device";

	return iodev.joys && strlen(iodev.joys[devid].label) == 0 ?
		"no identifier" : iodev.joys[devid].label;
}

void platform_event_process(arcan_evctx* ctx)
{
	SDL_Event event;
/* other fields will be set upon enqueue */
	arcan_event newevent = {.category = EVENT_IO};

	while (SDL_PollEvent(&event)) {
		switch (event.type) {
		case SDL_MOUSEBUTTONDOWN:
			newevent.io.kind = EVENT_IO_BUTTON;
			newevent.io.datatype = EVENT_IDATATYPE_DIGITAL;
			newevent.io.devkind  = EVENT_IDEVKIND_MOUSE;
			switch(event.button.button){
			case SDL_BUTTON_LEFT: newevent.io.subid = 1; break;
			case SDL_BUTTON_MIDDLE: newevent.io.subid = 2; break;
			case SDL_BUTTON_RIGHT: newevent.io.subid = 3; break;
			default:
				newevent.io.subid = event.button.button;
			break;
			}
			newevent.io.devid = event.button.which;
			newevent.io.input.digital.active = true;
			snprintf(newevent.io.label, sizeof(newevent.io.label) - 1, "mouse%i",
				event.motion.which);
			arcan_event_enqueue(ctx, &newevent);
		break;

		case SDL_MOUSEBUTTONUP:
			newevent.io.kind = EVENT_IO_BUTTON;
			newevent.io.datatype = EVENT_IDATATYPE_DIGITAL;
			newevent.io.devkind  = EVENT_IDEVKIND_MOUSE;
			newevent.io.devid = event.button.which;
			newevent.io.subid = event.button.button;
			newevent.io.input.digital.active = false;
			snprintf(newevent.io.label, sizeof(newevent.io.label) - 1, "mouse%i",
				event.motion.which);
			arcan_event_enqueue(ctx, &newevent);
		break;

		case SDL_MOUSEMOTION:
			process_mousemotion(ctx, &event.motion);
		break;

		case SDL_JOYAXISMOTION:
			process_axismotion(ctx, &event.jaxis);
		break;

		case SDL_KEYDOWN:
			newevent.io.datatype = EVENT_IDATATYPE_TRANSLATED;
			newevent.io.devkind  = EVENT_IDEVKIND_KEYBOARD;
			newevent.io.input.translated.active = true;
			newevent.io.input.translated.keysym = event.key.keysym.sym;
			newevent.io.input.translated.modifiers = event.key.keysym.mod;
			newevent.io.input.translated.scancode = event.key.keysym.scancode;
			newevent.io.subid = event.key.keysym.unicode;
			if (!((event.key.keysym.mod & (ARKMOD_LCTRL | ARKMOD_RCTRL)) > 0))
				to_utf8(event.key.keysym.unicode, newevent.io.input.translated.utf8);
			arcan_event_enqueue(ctx, &newevent);
		break;

		case SDL_KEYUP:
			newevent.io.datatype = EVENT_IDATATYPE_TRANSLATED;
			newevent.io.devkind  = EVENT_IDEVKIND_KEYBOARD;
			newevent.io.input.translated.active = false;
			newevent.io.input.translated.keysym = event.key.keysym.sym;
			newevent.io.input.translated.modifiers = event.key.keysym.mod;
			newevent.io.input.translated.scancode = event.key.keysym.scancode;
			newevent.io.subid = event.key.keysym.unicode;
			arcan_event_enqueue(ctx, &newevent);
		break;

		case SDL_JOYBUTTONDOWN:
			newevent.io.kind = EVENT_IO_BUTTON;
			newevent.io.datatype = EVENT_IDATATYPE_DIGITAL;
			newevent.io.devkind  = EVENT_IDEVKIND_GAMEDEV;
			newevent.io.devid = iodev.joys[event.jbutton.which].devnum;
			newevent.io.subid = event.jbutton.button;
			newevent.io.input.digital.active = true;
			snprintf(newevent.io.label, sizeof(newevent.io.label)-1,
				"joystick%i", event.jbutton.which);
			arcan_event_enqueue(ctx, &newevent);
		break;

		case SDL_JOYBUTTONUP:
			newevent.io.kind = EVENT_IO_BUTTON;
			newevent.io.datatype = EVENT_IDATATYPE_DIGITAL;
			newevent.io.devkind  = EVENT_IDEVKIND_GAMEDEV;
			newevent.io.devid = iodev.joys[event.jbutton.which].devnum;
			newevent.io.subid = event.jbutton.button;
			newevent.io.input.digital.active = false;
			snprintf(newevent.io.label, sizeof(newevent.io.label)-1, "joystick%i",
				event.jbutton.which);
			arcan_event_enqueue(ctx, &newevent);
		break;

/* don't got any devices that actually use this to test with,
 * but should really just be translated into analog/digital events */
		case SDL_JOYBALLMOTION:
		break;

		case SDL_JOYHATMOTION:
			process_hatmotion(ctx, event.jhat.which, event.jhat.hat, event.jhat.value);
		break;

		case SDL_ACTIVEEVENT:
//newevent.io.kind = (MOUSEFOCUS, INPUTFOCUS, APPACTIVE(0 = icon, 1 = restored)
//if (event->active.state & SDL_APPINPUTFOCUS){
//	SDL_SetModState(KMOD_NONE);
		break;

		case SDL_QUIT:
			newevent.category = EVENT_SYSTEM;
			newevent.sys.kind = EVENT_SYSTEM_EXIT;
			arcan_event_enqueue(ctx, &newevent);
		break;

		case SDL_SYSWMEVENT:
			break;
/*
 * currently ignoring these events (and a resizeable window frame isn't yet
 * supported, although the video- code is capable of handling a rebuild/reinit,
 * the lua- scripts themselves all depend quite a bit on VRESH/VRESW, one
 * option would be to just calculate a scale factor for the newvresh, newvresw
 * and apply that as a translation step when passing the lua<->core border.
 *
 * Recently, changes in the egl-dri and arcan_lwa platforms makes this possible
 * so maybe it is time to update a little here ;-)
	case SDL_VIDEORESIZE:
	break;

	case SDL_VIDEOEXPOSE:
	break;

	case SDL_ACTIVEEVENT:
	break;

	case SDL_ */
	}
	}
}