shithub: snippets

ref: 0cd57b4514cb22dc3304f523680a1679e6e0479b
dir: /kbd.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <keyboard.h>
#include "kbd.h"

/*

example

void
threadmain(int, char**)
{
	Kbdctl *kctl;
	Key k;
	Alt a[] = {
		{ nil, &k, CHANRCV },
		{ nil, nil, CHANEND },
	};

	kctl = initkbd();
	if(kctl == nil)
		sysfatal("initkbd: %r");
	a[0].c = kctl->c;
	for(;;){
		if(alt(a) == 0){
			if(k.k == Kdel)
				break;
			else
				fprint(2, "KEY '%C' (mods=%b)\n", k.k, k.mods);
		}
	}
	closekbd(kctl);
	threadexitsall(nil);
}
*/

static void
kbdproc(void *v)
{
	Kbdctl *kc;
	char buf[128], buf2[128], *s;
	long n;
	Rune r;
	Key k;
	int mods = 0;

	kc = v;
	threadsetname("kbdproc");
	buf[0] = 0;
	buf2[0] = 0;
	buf2[1] = 0;
	while(kc->fd >= 0){
		if(buf[0] != 0){
			n = strlen(buf)+1;
			memmove(buf, buf+n, sizeof(buf)-n);
		}
		if (buf[0] == 0) {
			n = read(kc->fd, buf, sizeof(buf)-1);
			if (n <= 0){
				yield();
				if(kc->fd < 0)
					threadexits(nil);
				break;
			}
			buf[n-1] = 0;
			buf[n] = 0;
		}
		switch(buf[0]){
		case 'c':
			if(chartorune(&r, buf+1) > 0 && r != Runeerror){
				k = (Key){ r, mods };
				nbsend(kc->c, &k);
			}
		default:
			continue;
		case 'k':
			s = buf+1;
			while(*s){
				s += chartorune(&r, s);
				if(utfrune(buf2+1, r) == nil){
					if(r == Kctl)
						mods |= Mctrl;
					else if(r == Kalt)
						mods |= Malt;
					else if(r == Kshift)
						mods |= Mshift;
					else{
						k = (Key){r, mods};
						send(kc->c, &k);
					}
				}
			}
			break;
		case 'K':
			s = buf2+1;
			while(*s){
				s += chartorune(&r, s);
				if(utfrune(buf+1, r) == nil) {
					if(r == Kctl)
						mods ^= Mctrl;
					else if(r == Kalt)
						mods ^= Malt;
					else if(r == Kshift)
						mods ^= Mshift;
				}
			}
			break;
		}
		strcpy(buf2, buf);
	}
}

Kbdctl*
initkbd(void)
{
	Kbdctl *kc;

	kc = malloc(sizeof *kc);
	if(kc == nil)
		return nil;
	kc->fd = open("/dev/kbd", OREAD);
	if(kc->fd < 0){
		free(kc);
		return nil;
	}
	kc->c = chancreate(sizeof(Key), 0);
	if(kc->c == nil){
		close(kc->fd);
		free(kc);
		return nil;
	}
	kc->pid = proccreate(kbdproc, kc, 8192);
	return kc;
}

void
closekbd(Kbdctl *kc)
{
	close(kc->fd);
	kc->fd = -1;
	threadint(kc->pid);
}