const char * gui_mouse_event_code2key (const char *code) { int i, x, y, code_utf8, length; double diff_x, diff_y, distance, angle, pi4; static char key[128]; const char *ptr_code; key[0] = '\0'; /* * mouse code must have at least: * one code (for event) + X + Y == 3 bytes or 3 UTF-8 chars */ code_utf8 = utf8_is_valid (code, NULL); length = (code_utf8) ? utf8_strlen (code) : (int)strlen (code); if (length < 3) return NULL; /* get coordinates and button */ if (code_utf8) { /* get coordinates using UTF-8 chars in code */ x = utf8_char_int (code + 1) - 33; ptr_code = utf8_next_char (code + 1); if (!ptr_code) return NULL; y = utf8_char_int (ptr_code) - 33; } else { /* get coordinates using ISO chars in code */ x = ((unsigned char)code[1]) - 33; y = ((unsigned char)code[2]) - 33; } if (x < 0) x = 0; if (y < 0) y = 0; /* ignore code if it's motion/end code received as first event */ if ((gui_mouse_event_index == 0) && (MOUSE_CODE_MOTION(code[0]) || MOUSE_CODE_END(code[0]))) { return NULL; } /* set data in "gui_mouse_event_xxx" */ gui_mouse_event_x[gui_mouse_event_index] = x; gui_mouse_event_y[gui_mouse_event_index] = y; if (gui_mouse_event_index == 0) gui_mouse_event_button = code[0]; if (gui_mouse_event_index == 0) gui_mouse_event_index = 1; /* * browse wheel codes, if one code is found, return event name immediately */ for (i = 0; gui_mouse_wheel_codes[i][0]; i++) { if (code[0] == gui_mouse_wheel_codes[i][0][0]) { strcat (key, gui_mouse_wheel_codes[i][1]); gui_mouse_event_x[1] = gui_mouse_event_x[0]; gui_mouse_event_y[1] = gui_mouse_event_y[0]; return key; } } /* add name of button event */ for (i = 0; gui_mouse_button_codes[i][0]; i++) { if (gui_mouse_event_button == gui_mouse_button_codes[i][0][0]) { strcat (key, gui_mouse_button_codes[i][1]); break; } } /* nothing found, reset now or mouse will be stuck */ if (!key[0]) { gui_mouse_event_reset (); return NULL; } if (!MOUSE_CODE_END(code[0])) { strcat (key, "-event-"); if (MOUSE_CODE_MOTION(code[0])) { strcat (key, "drag"); } else { gui_mouse_event_x[1] = gui_mouse_event_x[0]; gui_mouse_event_y[1] = gui_mouse_event_y[0]; strcat (key, "down"); } return key; } /* * Mouse gesture: if (x,y) on release is different from (x,y) on click, * compute distance and angle between 2 points. * * Distance: sqrt((x2-x1)²+(y2-y1)²) * Angle : atan2(x1-x1, y2-y1) * * Angle: * * 3.14 pi * /\ * -2.35 || 2.35 3/4 * pi * || * -1.57 /----++----\ 1.57 1/2 * pi * \----++----/ * || * -0.78 || 0.78 1/4 * pi * \/ * 0.00 0 * * Possible returned gestures are: * * key name | dist. | angle * ---------------------------+-------+-------------------------- * buttonX-gesture-up | 3..19 | -2.35..-3.14 + 2.35..3.14 * buttonX-gesture-up-long | >= 20 | * buttonX-gesture-down | 3..19 | -0.78..0.78 * buttonX-gesture-down-long | >= 20 | * buttonX-gesture-left | 3..39 | -0.78..-2.35 * buttonX-gesture-left-long | >= 40 | * buttonX-gesture-right | 3..39 | 0.78..2.35 * buttonX-gesture-right-long | >= 40 | */ if (key[0] && ((gui_mouse_event_x[0] != gui_mouse_event_x[1]) || (gui_mouse_event_y[0] != gui_mouse_event_y[1]))) { diff_x = gui_mouse_event_x[1] - gui_mouse_event_x[0]; diff_y = gui_mouse_event_y[1] - gui_mouse_event_y[0]; distance = sqrt ((diff_x * diff_x) + (diff_y * diff_y)); if (distance >= 3) { angle = atan2 ((double)(gui_mouse_event_x[1] - gui_mouse_event_x[0]), (double)(gui_mouse_event_y[1] - gui_mouse_event_y[0])); pi4 = 3.14159265358979 / 4; if ((angle <= pi4 * (-3)) || (angle >= pi4 * 3)) { strcat (key, "-gesture-up"); if (distance >= 20) strcat (key, "-long"); } else if ((angle >= pi4 * (-1)) && (angle <= pi4)) { strcat (key, "-gesture-down"); if (distance >= 20) strcat (key, "-long"); } else if ((angle >= pi4 * (-3)) && (angle <= pi4 * (-1))) { strcat (key, "-gesture-left"); if (distance >= 40) strcat (key, "-long"); } else if ((angle >= pi4) && (angle <= pi4 * 3)) { strcat (key, "-gesture-right"); if (distance >= 40) strcat (key, "-long"); } } } return key; }
TEST(Utf8, Convert) { char result[5]; /* get UTF-8 char as integer */ BYTES_EQUAL(0, utf8_char_int (NULL)); BYTES_EQUAL(0, utf8_char_int ("")); BYTES_EQUAL(65, utf8_char_int ("ABC")); BYTES_EQUAL(235, utf8_char_int ("ë")); BYTES_EQUAL(0x20ac, utf8_char_int ("€")); BYTES_EQUAL(0x24b62, utf8_char_int (han_char)); BYTES_EQUAL(0x0, utf8_char_int ("\xc0\x80")); /* invalid */ BYTES_EQUAL(0x7f, utf8_char_int ("\xc1\xbf")); /* invalid */ BYTES_EQUAL(0x80, utf8_char_int ("\xc2\x80")); BYTES_EQUAL(0x7ff, utf8_char_int ("\xdf\xbf")); BYTES_EQUAL(0x0, utf8_char_int ("\xe0\x80\x80")); /* invalid */ BYTES_EQUAL(0x7ff, utf8_char_int ("\xe0\x9f\xbf")); /* invalid */ LONGS_EQUAL(0xd800, utf8_char_int ("\xed\xa0\x80")); /* invalid */ LONGS_EQUAL(0xdfff, utf8_char_int ("\xed\xbf\xbf")); /* invalid */ BYTES_EQUAL(0x800, utf8_char_int ("\xe0\xa0\x80")); BYTES_EQUAL(0xd7ff, utf8_char_int ("\xed\x9f\xbf")); BYTES_EQUAL(0xe000, utf8_char_int ("\xe7\x80\x80")); BYTES_EQUAL(0xffff, utf8_char_int ("\xef\xbf\xbf")); BYTES_EQUAL(0x0, utf8_char_int ("\xf0\x80\x80\x80")); /* invalid */ BYTES_EQUAL(0xffff, utf8_char_int ("\xf0\x8f\xbf\xbf")); /* invalid */ BYTES_EQUAL(0x10000, utf8_char_int ("\xf0\x90\x80\x80")); BYTES_EQUAL(0x1fffff, utf8_char_int ("\xf7\xbf\xbf\xbf")); /* convert unicode char to a string */ utf8_int_string (0, NULL); utf8_int_string (0, result); STRCMP_EQUAL("", result); utf8_int_string (235, result); STRCMP_EQUAL("ë", result); utf8_int_string (0x20ac, result); STRCMP_EQUAL("€", result); utf8_int_string (0x24b62, result); STRCMP_EQUAL(han_char, result); /* get wide char */ BYTES_EQUAL(WEOF, utf8_wide_char (NULL)); BYTES_EQUAL(WEOF, utf8_wide_char ("")); BYTES_EQUAL(65, utf8_wide_char ("A")); BYTES_EQUAL(0xc3ab, utf8_wide_char ("ë")); BYTES_EQUAL(0xe282ac, utf8_wide_char ("€")); BYTES_EQUAL(0xf0a4ada2, utf8_wide_char (han_char)); }
int utf8_is_valid (const char *string, char **error) { int code_point; while (string && string[0]) { /* * UTF-8, 2 bytes, should be: 110vvvvv 10vvvvvv * and in range: U+0080 - U+07FF */ if (((unsigned char)(string[0]) & 0xE0) == 0xC0) { if (!string[1] || (((unsigned char)(string[1]) & 0xC0) != 0x80)) goto invalid; code_point = utf8_char_int (string); if ((code_point < 0x0080) || (code_point > 0x07FF)) goto invalid; string += 2; } /* * UTF-8, 3 bytes, should be: 1110vvvv 10vvvvvv 10vvvvvv * and in range: U+0800 - U+FFFF * (note: high and low surrogate halves used by UTF-16 (U+D800 through * U+DFFF) are not legal Unicode values) */ else if (((unsigned char)(string[0]) & 0xF0) == 0xE0) { if (!string[1] || !string[2] || (((unsigned char)(string[1]) & 0xC0) != 0x80) || (((unsigned char)(string[2]) & 0xC0) != 0x80)) { goto invalid; } code_point = utf8_char_int (string); if ((code_point < 0x0800) || (code_point > 0xFFFF) || ((code_point >= 0xD800) && (code_point <= 0xDFFF))) { goto invalid; } string += 3; } /* * UTF-8, 4 bytes, should be: 11110vvv 10vvvvvv 10vvvvvv 10vvvvvv * and in range: U+10000 - U+1FFFFF */ else if (((unsigned char)(string[0]) & 0xF8) == 0xF0) { if (!string[1] || !string[2] || !string[3] || (((unsigned char)(string[1]) & 0xC0) != 0x80) || (((unsigned char)(string[2]) & 0xC0) != 0x80) || (((unsigned char)(string[3]) & 0xC0) != 0x80)) { goto invalid; } code_point = utf8_char_int(string); if ((code_point < 0x10000) || (code_point > 0x1FFFFF)) goto invalid; string += 4; } /* UTF-8, 1 byte, should be: 0vvvvvvv */ else if ((unsigned char)(string[0]) >= 0x80) goto invalid; else string++; } if (error) *error = NULL; return 1; invalid: if (error) *error = (char *)string; return 0; }