heartbeat

Simple server monitor system using encrypted messages over udp
git clone https://noulin.net/git/heartbeat.git
Log | Files | Refs | README

input.h (5264B)


      1 // if s1 starts with s2 returns true, else false
      2 // len is the length of s1
      3 // s2 should be null-terminated
      4 static bool starts_with(const char *s1, int len, const char *s2)
      5 {
      6 	int n = 0;
      7 	while (*s2 && n < len) {
      8 		if (*s1++ != *s2++)
      9 			return false;
     10 		n++;
     11 	}
     12 	return *s2 == 0;
     13 }
     14 
     15 static int parse_mouse_event(struct tb_event *event, const char *buf, int len) {
     16 	if (len >= 6 && starts_with(buf, len, "\033[M")) {
     17 		// X10 mouse encoding, the simplest one
     18 		// \033 [ M Cb Cx Cy
     19 		int b = buf[3] - 32;
     20 		switch (b & 3) {
     21 		case 0:
     22 			if ((b & 64) != 0)
     23 				event->key = TB_KEY_MOUSE_WHEEL_UP;
     24 			else
     25 				event->key = TB_KEY_MOUSE_LEFT;
     26 			break;
     27 		case 1:
     28 			if ((b & 64) != 0)
     29 				event->key = TB_KEY_MOUSE_WHEEL_DOWN;
     30 			else
     31 				event->key = TB_KEY_MOUSE_MIDDLE;
     32 			break;
     33 		case 2:
     34 			event->key = TB_KEY_MOUSE_RIGHT;
     35 			break;
     36 		case 3:
     37 			event->key = TB_KEY_MOUSE_RELEASE;
     38 			break;
     39 		default:
     40 			return -6;
     41 		}
     42 		event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default
     43 		if ((b & 32) != 0)
     44 			event->mod |= TB_MOD_MOTION;
     45 
     46 		// the coord is 1,1 for upper left
     47 		event->x = (uint8_t)buf[4] - 1 - 32;
     48 		event->y = (uint8_t)buf[5] - 1 - 32;
     49 
     50 		return 6;
     51 	} else if (starts_with(buf, len, "\033[<") || starts_with(buf, len, "\033[")) {
     52 		// xterm 1006 extended mode or urxvt 1015 extended mode
     53 		// xterm: \033 [ < Cb ; Cx ; Cy (M or m)
     54 		// urxvt: \033 [ Cb ; Cx ; Cy M
     55 		int i, mi = -1, starti = -1;
     56 		int isM, isU, s1 = -1, s2 = -1;
     57 		int n1 = 0, n2 = 0, n3 = 0;
     58 
     59 		for (i = 0; i < len; i++) {
     60 			// We search the first (s1) and the last (s2) ';'
     61 			if (buf[i] == ';') {
     62 				if (s1 == -1)
     63 					s1 = i;
     64 				s2 = i;
     65 			}
     66 
     67 			// We search for the first 'm' or 'M'
     68 			if ((buf[i] == 'm' || buf[i] == 'M') && mi == -1) {
     69 				mi = i;
     70 				break;
     71 			}
     72 		}
     73 		if (mi == -1)
     74 			return 0;
     75 
     76 		// whether it's a capital M or not
     77 		isM = (buf[mi] == 'M');
     78 
     79 		if (buf[2] == '<') {
     80 			isU = 0;
     81 			starti = 3;
     82 		} else {
     83 			isU = 1;
     84 			starti = 2;
     85 		}
     86 
     87 		if (s1 == -1 || s2 == -1 || s1 == s2)
     88 			return 0;
     89 
     90 		n1 = strtoul(&buf[starti], NULL, 10);
     91 		n2 = strtoul(&buf[s1 + 1], NULL, 10);
     92 		n3 = strtoul(&buf[s2 + 1], NULL, 10);
     93 
     94 		if (isU)
     95 			n1 -= 32;
     96 
     97 		switch (n1 & 3) {
     98 		case 0:
     99 			if ((n1&64) != 0) {
    100 				event->key = TB_KEY_MOUSE_WHEEL_UP;
    101 			} else {
    102 				event->key = TB_KEY_MOUSE_LEFT;
    103 			}
    104 			break;
    105 		case 1:
    106 			if ((n1&64) != 0) {
    107 				event->key = TB_KEY_MOUSE_WHEEL_DOWN;
    108 			} else {
    109 				event->key = TB_KEY_MOUSE_MIDDLE;
    110 			}
    111 			break;
    112 		case 2:
    113 			event->key = TB_KEY_MOUSE_RIGHT;
    114 			break;
    115 		case 3:
    116 			event->key = TB_KEY_MOUSE_RELEASE;
    117 			break;
    118 		default:
    119 			return mi + 1;
    120 		}
    121 
    122 		if (!isM) {
    123 			// on xterm mouse release is signaled by lowercase m
    124 			event->key = TB_KEY_MOUSE_RELEASE;
    125 		}
    126 
    127 		event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default
    128 		if ((n1&32) != 0)
    129 			event->mod |= TB_MOD_MOTION;
    130 
    131 		event->x = n2 - 1;
    132 		event->y = n3 - 1;
    133 
    134 		return mi + 1;
    135 	}
    136 
    137 	return 0;
    138 }
    139 
    140 // convert escape sequence to event, and return consumed bytes on success (failure == 0)
    141 static int parse_escape_seq(struct tb_event *event, const char *buf, int len)
    142 {
    143 	int mouse_parsed = parse_mouse_event(event, buf, len);
    144 
    145 	if (mouse_parsed != 0)
    146 		return mouse_parsed;
    147 
    148 	// it's pretty simple here, find 'starts_with' match and return
    149 	// success, else return failure
    150 	int i;
    151 	for (i = 0; keys[i]; i++) {
    152 		if (starts_with(buf, len, keys[i])) {
    153 			event->ch = 0;
    154 			event->key = 0xFFFF-i;
    155 			return strlen(keys[i]);
    156 		}
    157 	}
    158 	return 0;
    159 }
    160 
    161 static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf, int inputmode)
    162 {
    163 	const char *buf = inbuf->buf;
    164 	const int len = inbuf->len;
    165 	if (len == 0)
    166 		return false;
    167 
    168 	if (buf[0] == '\033') {
    169 		int n = parse_escape_seq(event, buf, len);
    170 		if (n != 0) {
    171 			bool success = true;
    172 			if (n < 0) {
    173 				success = false;
    174 				n = -n;
    175 			}
    176 			bytebuffer_truncate(inbuf, n);
    177 			return success;
    178 		} else {
    179 			// it's not escape sequence, then it's ALT or ESC,
    180 			// check inputmode
    181 			if (inputmode&TB_INPUT_ESC) {
    182 				// if we're in escape mode, fill ESC event, pop
    183 				// buffer, return success
    184 				event->ch = 0;
    185 				event->key = TB_KEY_ESC;
    186 				event->mod = 0;
    187 				bytebuffer_truncate(inbuf, 1);
    188 				return true;
    189 			} else if (inputmode&TB_INPUT_ALT) {
    190 				// if we're in alt mode, set ALT modifier to
    191 				// event and redo parsing
    192 				event->mod = TB_MOD_ALT;
    193 				bytebuffer_truncate(inbuf, 1);
    194 				return extract_event(event, inbuf, inputmode);
    195 			}
    196 			assert(!"never got here");
    197 		}
    198 	}
    199 
    200 	// if we're here, this is not an escape sequence and not an alt sequence
    201 	// so, it's a FUNCTIONAL KEY or a UNICODE character
    202 
    203 	// first of all check if it's a functional key
    204 	if ((unsigned char)buf[0] <= TB_KEY_SPACE ||
    205 	    (unsigned char)buf[0] == TB_KEY_BACKSPACE2)
    206 	{
    207 		// fill event, pop buffer, return success */
    208 		event->ch = 0;
    209 		event->key = (uint16_t)buf[0];
    210 		bytebuffer_truncate(inbuf, 1);
    211 		return true;
    212 	}
    213 
    214 	// feh... we got utf8 here
    215 
    216 	// check if there is all bytes
    217 	if (len >= tb_utf8_char_length(buf[0])) {
    218 		/* everything ok, fill event, pop buffer, return success */
    219 		tb_utf8_char_to_unicode(&event->ch, buf);
    220 		event->key = 0;
    221 		bytebuffer_truncate(inbuf, tb_utf8_char_length(buf[0]));
    222 		return true;
    223 	}
    224 
    225 	// event isn't recognized, perhaps there is not enough bytes in utf8
    226 	// sequence
    227 	return false;
    228 }