2013-11-17 11:19:50 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2008 Kristian Høgsberg
|
2015-05-28 08:23:59 +10:00
|
|
|
* Copyright © 2013-2015 Red Hat, Inc.
|
2013-11-17 11:19:50 +01:00
|
|
|
*
|
2015-06-11 12:09:18 +10:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
2013-11-17 11:19:50 +01:00
|
|
|
*
|
2015-06-11 12:09:18 +10:00
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
2013-11-17 11:19:50 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef LIBINPUT_UTIL_H
|
|
|
|
|
#define LIBINPUT_UTIL_H
|
|
|
|
|
|
2016-07-07 17:39:37 +10:00
|
|
|
#include "config.h"
|
|
|
|
|
|
2016-02-04 08:31:25 +10:00
|
|
|
#include <assert.h>
|
2016-11-24 10:48:39 +10:00
|
|
|
#include <errno.h>
|
2016-05-25 13:29:32 +10:00
|
|
|
#include <limits.h>
|
2016-11-24 10:51:26 +10:00
|
|
|
#include <locale.h>
|
2014-07-14 16:19:33 +10:00
|
|
|
#include <math.h>
|
2015-05-28 19:01:01 -07:00
|
|
|
#include <stdarg.h>
|
2015-06-30 12:00:53 +10:00
|
|
|
#include <stdbool.h>
|
2017-05-14 16:33:16 +02:00
|
|
|
#include <stddef.h>
|
2015-05-28 19:01:01 -07:00
|
|
|
#include <stdio.h>
|
2014-08-26 09:37:29 +10:00
|
|
|
#include <string.h>
|
2014-09-01 16:47:28 +10:00
|
|
|
#include <time.h>
|
2016-11-24 10:51:05 +10:00
|
|
|
#include <unistd.h>
|
2014-06-20 14:06:19 +10:00
|
|
|
|
2013-11-23 12:55:44 +01:00
|
|
|
#include "libinput.h"
|
|
|
|
|
|
2015-05-22 16:07:10 +10:00
|
|
|
#define VENDOR_ID_APPLE 0x5ac
|
2016-12-19 15:36:34 +10:00
|
|
|
#define VENDOR_ID_CHICONY 0x4f2
|
2016-04-21 15:08:23 +10:00
|
|
|
#define VENDOR_ID_LOGITECH 0x46d
|
2015-05-22 16:07:10 +10:00
|
|
|
#define VENDOR_ID_WACOM 0x56a
|
2015-07-16 16:05:48 +10:00
|
|
|
#define VENDOR_ID_SYNAPTICS_SERIAL 0x002
|
2015-12-13 22:27:55 -08:00
|
|
|
#define PRODUCT_ID_APPLE_KBD_TOUCHPAD 0x273
|
2017-01-10 09:22:16 +10:00
|
|
|
#define PRODUCT_ID_APPLE_APPLETOUCH 0x21a
|
2015-07-16 16:05:48 +10:00
|
|
|
#define PRODUCT_ID_SYNAPTICS_SERIAL 0x007
|
2017-08-30 15:53:01 +10:00
|
|
|
#define PRODUCT_ID_WACOM_EKR 0x0331
|
2015-05-22 16:07:10 +10:00
|
|
|
|
2015-06-19 16:03:42 +10:00
|
|
|
/* The HW DPI rate we normalize to before calculating pointer acceleration */
|
|
|
|
|
#define DEFAULT_MOUSE_DPI 1000
|
2017-05-16 13:01:32 +10:00
|
|
|
#define DEFAULT_TRACKPOINT_RANGE 20
|
|
|
|
|
#define DEFAULT_TRACKPOINT_SENSITIVITY 128
|
2015-06-19 16:03:42 +10:00
|
|
|
|
2017-03-28 11:48:52 +10:00
|
|
|
#define ANSI_HIGHLIGHT "\x1B[0;1;39m"
|
|
|
|
|
#define ANSI_RED "\x1B[0;31m"
|
|
|
|
|
#define ANSI_GREEN "\x1B[0;32m"
|
|
|
|
|
#define ANSI_YELLOW "\x1B[0;33m"
|
|
|
|
|
#define ANSI_BLUE "\x1B[0;34m"
|
|
|
|
|
#define ANSI_MAGENTA "\x1B[0;35m"
|
|
|
|
|
#define ANSI_CYAN "\x1B[0;36m"
|
|
|
|
|
#define ANSI_BRIGHT_RED "\x1B[0;31;1m"
|
|
|
|
|
#define ANSI_BRIGHT_GREEN "\x1B[0;32;1m"
|
|
|
|
|
#define ANSI_BRIGHT_YELLOW "\x1B[0;33;1m"
|
|
|
|
|
#define ANSI_BRIGHT_BLUE "\x1B[0;34;1m"
|
|
|
|
|
#define ANSI_BRIGHT_MAGENTA "\x1B[0;35;1m"
|
|
|
|
|
#define ANSI_BRIGHT_CYAN "\x1B[0;36;1m"
|
|
|
|
|
#define ANSI_NORMAL "\x1B[0m"
|
2017-03-28 11:31:16 +10:00
|
|
|
|
2015-12-14 07:33:31 +10:00
|
|
|
#define CASE_RETURN_STRING(a) case a: return #a
|
2015-07-20 14:37:37 +10:00
|
|
|
|
2013-11-17 11:19:50 +01:00
|
|
|
/*
|
|
|
|
|
* This list data structure is a verbatim copy from wayland-util.h from the
|
|
|
|
|
* Wayland project; except that wl_ prefix has been removed.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
struct list {
|
|
|
|
|
struct list *prev;
|
|
|
|
|
struct list *next;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void list_init(struct list *list);
|
|
|
|
|
void list_insert(struct list *list, struct list *elm);
|
2018-05-23 15:21:56 +10:00
|
|
|
void list_append(struct list *list, struct list *elm);
|
2013-11-17 11:19:50 +01:00
|
|
|
void list_remove(struct list *elm);
|
2016-07-12 11:03:03 +10:00
|
|
|
bool list_empty(const struct list *list);
|
2013-11-17 11:19:50 +01:00
|
|
|
|
2017-05-15 13:08:17 +02:00
|
|
|
#define container_of(ptr, type, member) \
|
|
|
|
|
(__typeof__(type) *)((char *)(ptr) - \
|
|
|
|
|
offsetof(__typeof__(type), member))
|
|
|
|
|
|
|
|
|
|
#define list_first_entry(head, pos, member) \
|
|
|
|
|
container_of((head)->next, __typeof__(*pos), member)
|
2013-11-17 11:19:50 +01:00
|
|
|
|
|
|
|
|
#define list_for_each(pos, head, member) \
|
2017-05-15 13:08:17 +02:00
|
|
|
for (pos = 0, pos = list_first_entry(head, pos, member); \
|
2013-11-17 11:19:50 +01:00
|
|
|
&pos->member != (head); \
|
2017-05-15 13:08:17 +02:00
|
|
|
pos = list_first_entry(&pos->member, pos, member))
|
2013-11-17 11:19:50 +01:00
|
|
|
|
|
|
|
|
#define list_for_each_safe(pos, tmp, head, member) \
|
2018-02-27 09:43:21 +10:00
|
|
|
for (pos = 0, tmp = 0, \
|
2017-05-15 13:08:17 +02:00
|
|
|
pos = list_first_entry(head, pos, member), \
|
|
|
|
|
tmp = list_first_entry(&pos->member, tmp, member); \
|
2013-11-17 11:19:50 +01:00
|
|
|
&pos->member != (head); \
|
|
|
|
|
pos = tmp, \
|
2017-05-15 13:08:17 +02:00
|
|
|
tmp = list_first_entry(&pos->member, tmp, member))
|
2013-11-17 11:19:50 +01:00
|
|
|
|
2016-06-02 15:35:43 +10:00
|
|
|
#define NBITS(b) (b * 8)
|
2014-07-27 15:43:59 +02:00
|
|
|
#define LONG_BITS (sizeof(long) * 8)
|
|
|
|
|
#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
|
2013-11-17 11:19:50 +01:00
|
|
|
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
|
2013-12-06 14:35:22 +10:00
|
|
|
#define ARRAY_FOR_EACH(_arr, _elem) \
|
2014-08-22 15:08:57 +10:00
|
|
|
for (size_t _i = 0; _i < ARRAY_LENGTH(_arr) && (_elem = &_arr[_i]); _i++)
|
2014-12-24 11:10:04 +10:00
|
|
|
#define AS_MASK(v) (1 << (v))
|
2013-11-17 11:19:50 +01:00
|
|
|
|
2014-02-06 15:26:02 +10:00
|
|
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
|
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
2015-05-26 08:46:05 +10:00
|
|
|
#define streq(s1, s2) (strcmp((s1), (s2)) == 0)
|
|
|
|
|
#define strneq(s1, s2, n) (strncmp((s1), (s2), (n)) == 0)
|
2014-02-06 15:26:02 +10:00
|
|
|
|
2014-06-05 23:20:36 -04:00
|
|
|
#define NCHARS(x) ((size_t)(((x) + 7) / 8))
|
|
|
|
|
|
2015-06-24 15:30:59 +10:00
|
|
|
#ifdef DEBUG_TRACE
|
|
|
|
|
#define debug_trace(...) \
|
|
|
|
|
do { \
|
|
|
|
|
printf("%s:%d %s() - ", __FILE__, __LINE__, __func__); \
|
|
|
|
|
printf(__VA_ARGS__); \
|
|
|
|
|
} while (0)
|
|
|
|
|
#else
|
|
|
|
|
#define debug_trace(...) { }
|
|
|
|
|
#endif
|
2015-06-29 13:56:05 +10:00
|
|
|
|
2013-11-17 11:19:50 +01:00
|
|
|
#define LIBINPUT_EXPORT __attribute__ ((visibility("default")))
|
|
|
|
|
|
2013-12-06 14:47:09 +10:00
|
|
|
static inline void *
|
|
|
|
|
zalloc(size_t size)
|
|
|
|
|
{
|
2017-07-07 09:42:59 +10:00
|
|
|
void *p;
|
|
|
|
|
|
2018-06-11 11:13:03 +10:00
|
|
|
if ((ssize_t)size < 0)
|
|
|
|
|
abort();
|
|
|
|
|
|
2017-07-07 09:42:59 +10:00
|
|
|
p = calloc(1, size);
|
|
|
|
|
if (!p)
|
|
|
|
|
abort();
|
|
|
|
|
|
|
|
|
|
return p;
|
2013-12-06 14:47:09 +10:00
|
|
|
}
|
|
|
|
|
|
2017-07-07 09:47:06 +10:00
|
|
|
/**
|
|
|
|
|
* strdup guaranteed to succeed. If the input string is NULL, the output
|
|
|
|
|
* string is NULL. If the input string is a string pointer, we strdup or
|
|
|
|
|
* abort on failure.
|
|
|
|
|
*/
|
|
|
|
|
static inline char*
|
|
|
|
|
safe_strdup(const char *str)
|
|
|
|
|
{
|
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
|
|
if (!str)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
s = strdup(str);
|
|
|
|
|
if (!s)
|
|
|
|
|
abort();
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-21 21:52:57 -04:00
|
|
|
/* This bitfield helper implementation is taken from from libevdev-util.h,
|
|
|
|
|
* except that it has been modified to work with arrays of unsigned chars
|
|
|
|
|
*/
|
|
|
|
|
|
2016-07-12 11:03:03 +10:00
|
|
|
static inline bool
|
2014-05-21 21:52:57 -04:00
|
|
|
bit_is_set(const unsigned char *array, int bit)
|
|
|
|
|
{
|
2016-07-13 07:30:40 +10:00
|
|
|
return !!(array[bit / 8] & (1 << (bit % 8)));
|
2014-05-21 21:52:57 -04:00
|
|
|
}
|
|
|
|
|
|
2016-07-13 07:30:40 +10:00
|
|
|
static inline void
|
2014-05-21 21:52:57 -04:00
|
|
|
set_bit(unsigned char *array, int bit)
|
|
|
|
|
{
|
2016-07-13 07:30:40 +10:00
|
|
|
array[bit / 8] |= (1 << (bit % 8));
|
2014-05-21 21:52:57 -04:00
|
|
|
}
|
|
|
|
|
|
2016-07-13 07:30:40 +10:00
|
|
|
static inline void
|
2014-05-21 21:52:57 -04:00
|
|
|
clear_bit(unsigned char *array, int bit)
|
|
|
|
|
{
|
2016-07-13 07:30:40 +10:00
|
|
|
array[bit / 8] &= ~(1 << (bit % 8));
|
2014-05-21 21:52:57 -04:00
|
|
|
}
|
|
|
|
|
|
2014-06-20 14:06:19 +10:00
|
|
|
static inline void
|
|
|
|
|
msleep(unsigned int ms)
|
|
|
|
|
{
|
|
|
|
|
usleep(ms * 1000);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-12 11:03:03 +10:00
|
|
|
static inline bool
|
2014-07-27 15:43:59 +02:00
|
|
|
long_bit_is_set(const unsigned long *array, int bit)
|
|
|
|
|
{
|
2016-02-05 10:15:35 +10:00
|
|
|
return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
|
2014-07-27 15:43:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
long_set_bit(unsigned long *array, int bit)
|
|
|
|
|
{
|
2016-02-05 10:15:35 +10:00
|
|
|
array[bit / LONG_BITS] |= (1LL << (bit % LONG_BITS));
|
2014-07-27 15:43:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
long_clear_bit(unsigned long *array, int bit)
|
|
|
|
|
{
|
2016-02-05 10:15:35 +10:00
|
|
|
array[bit / LONG_BITS] &= ~(1LL << (bit % LONG_BITS));
|
2014-07-27 15:43:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
long_set_bit_state(unsigned long *array, int bit, int state)
|
|
|
|
|
{
|
|
|
|
|
if (state)
|
|
|
|
|
long_set_bit(array, bit);
|
|
|
|
|
else
|
|
|
|
|
long_clear_bit(array, bit);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-12 11:03:03 +10:00
|
|
|
static inline bool
|
2016-02-04 08:31:25 +10:00
|
|
|
long_any_bit_set(unsigned long *array, size_t size)
|
|
|
|
|
{
|
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
|
|
assert(size > 0);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
|
if (array[i] != 0)
|
2016-07-12 11:03:03 +10:00
|
|
|
return true;
|
|
|
|
|
return false;
|
2016-02-04 08:31:25 +10:00
|
|
|
}
|
|
|
|
|
|
2016-05-03 13:52:53 +10:00
|
|
|
static inline double
|
|
|
|
|
deg2rad(int degree)
|
|
|
|
|
{
|
|
|
|
|
return M_PI * degree / 180.0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-26 09:37:29 +10:00
|
|
|
struct matrix {
|
|
|
|
|
float val[3][3]; /* [row][col] */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
matrix_init_identity(struct matrix *m)
|
|
|
|
|
{
|
|
|
|
|
memset(m, 0, sizeof(*m));
|
|
|
|
|
m->val[0][0] = 1;
|
|
|
|
|
m->val[1][1] = 1;
|
|
|
|
|
m->val[2][2] = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
matrix_from_farray6(struct matrix *m, const float values[6])
|
|
|
|
|
{
|
|
|
|
|
matrix_init_identity(m);
|
|
|
|
|
m->val[0][0] = values[0];
|
|
|
|
|
m->val[0][1] = values[1];
|
|
|
|
|
m->val[0][2] = values[2];
|
|
|
|
|
m->val[1][0] = values[3];
|
|
|
|
|
m->val[1][1] = values[4];
|
|
|
|
|
m->val[1][2] = values[5];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
matrix_init_scale(struct matrix *m, float sx, float sy)
|
|
|
|
|
{
|
|
|
|
|
matrix_init_identity(m);
|
|
|
|
|
m->val[0][0] = sx;
|
|
|
|
|
m->val[1][1] = sy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
matrix_init_translate(struct matrix *m, float x, float y)
|
|
|
|
|
{
|
|
|
|
|
matrix_init_identity(m);
|
|
|
|
|
m->val[0][2] = x;
|
|
|
|
|
m->val[1][2] = y;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-03 13:52:53 +10:00
|
|
|
static inline void
|
|
|
|
|
matrix_init_rotate(struct matrix *m, int degrees)
|
|
|
|
|
{
|
|
|
|
|
double s, c;
|
|
|
|
|
|
|
|
|
|
s = sin(deg2rad(degrees));
|
|
|
|
|
c = cos(deg2rad(degrees));
|
|
|
|
|
|
|
|
|
|
matrix_init_identity(m);
|
|
|
|
|
m->val[0][0] = c;
|
|
|
|
|
m->val[0][1] = -s;
|
|
|
|
|
m->val[1][0] = s;
|
|
|
|
|
m->val[1][1] = c;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-12 11:03:03 +10:00
|
|
|
static inline bool
|
2016-05-03 13:44:04 +10:00
|
|
|
matrix_is_identity(const struct matrix *m)
|
2014-08-26 09:37:29 +10:00
|
|
|
{
|
|
|
|
|
return (m->val[0][0] == 1 &&
|
|
|
|
|
m->val[0][1] == 0 &&
|
|
|
|
|
m->val[0][2] == 0 &&
|
|
|
|
|
m->val[1][0] == 0 &&
|
|
|
|
|
m->val[1][1] == 1 &&
|
|
|
|
|
m->val[1][2] == 0 &&
|
|
|
|
|
m->val[2][0] == 0 &&
|
|
|
|
|
m->val[2][1] == 0 &&
|
|
|
|
|
m->val[2][2] == 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
matrix_mult(struct matrix *dest,
|
|
|
|
|
const struct matrix *m1,
|
|
|
|
|
const struct matrix *m2)
|
|
|
|
|
{
|
|
|
|
|
struct matrix m; /* allow for dest == m1 or dest == m2 */
|
|
|
|
|
int row, col, i;
|
|
|
|
|
|
|
|
|
|
for (row = 0; row < 3; row++) {
|
|
|
|
|
for (col = 0; col < 3; col++) {
|
|
|
|
|
double v = 0;
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
|
v += m1->val[row][i] * m2->val[i][col];
|
|
|
|
|
}
|
|
|
|
|
m.val[row][col] = v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(dest, &m, sizeof(m));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
2016-05-03 13:44:04 +10:00
|
|
|
matrix_mult_vec(const struct matrix *m, int *x, int *y)
|
2014-08-26 09:37:29 +10:00
|
|
|
{
|
|
|
|
|
int tx, ty;
|
|
|
|
|
|
|
|
|
|
tx = *x * m->val[0][0] + *y * m->val[0][1] + m->val[0][2];
|
|
|
|
|
ty = *x * m->val[1][0] + *y * m->val[1][1] + m->val[1][2];
|
|
|
|
|
|
|
|
|
|
*x = tx;
|
|
|
|
|
*y = ty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
matrix_to_farray6(const struct matrix *m, float out[6])
|
|
|
|
|
{
|
|
|
|
|
out[0] = m->val[0][0];
|
|
|
|
|
out[1] = m->val[0][1];
|
|
|
|
|
out[2] = m->val[0][2];
|
|
|
|
|
out[3] = m->val[1][0];
|
|
|
|
|
out[4] = m->val[1][1];
|
|
|
|
|
out[5] = m->val[1][2];
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-06 15:26:49 +10:00
|
|
|
static inline void
|
|
|
|
|
matrix_to_relative(struct matrix *dest, const struct matrix *src)
|
|
|
|
|
{
|
|
|
|
|
matrix_init_identity(dest);
|
|
|
|
|
dest->val[0][0] = src->val[0][0];
|
|
|
|
|
dest->val[0][1] = src->val[0][1];
|
|
|
|
|
dest->val[1][0] = src->val[1][0];
|
|
|
|
|
dest->val[1][1] = src->val[1][1];
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-28 19:01:01 -07:00
|
|
|
/**
|
|
|
|
|
* Simple wrapper for asprintf that ensures the passed in-pointer is set
|
|
|
|
|
* to NULL upon error.
|
|
|
|
|
* The standard asprintf() call does not guarantee the passed in pointer
|
|
|
|
|
* will be NULL'ed upon failure, whereas this wrapper does.
|
|
|
|
|
*
|
|
|
|
|
* @param strp pointer to set to newly allocated string.
|
|
|
|
|
* This pointer should be passed to free() to release when done.
|
|
|
|
|
* @param fmt the format string to use for printing.
|
|
|
|
|
* @return The number of bytes printed (excluding the null byte terminator)
|
|
|
|
|
* upon success or -1 upon failure. In the case of failure the pointer is set
|
|
|
|
|
* to NULL.
|
|
|
|
|
*/
|
2017-07-03 12:45:12 +10:00
|
|
|
LIBINPUT_ATTRIBUTE_PRINTF(2, 3)
|
2015-05-28 19:01:01 -07:00
|
|
|
static inline int
|
|
|
|
|
xasprintf(char **strp, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
|
rc = vasprintf(strp, fmt, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
if ((rc == -1) && strp)
|
|
|
|
|
*strp = NULL;
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-05 13:32:16 +01:00
|
|
|
enum ratelimit_state {
|
|
|
|
|
RATELIMIT_EXCEEDED,
|
|
|
|
|
RATELIMIT_THRESHOLD,
|
|
|
|
|
RATELIMIT_PASS,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ratelimit {
|
|
|
|
|
uint64_t interval;
|
|
|
|
|
uint64_t begin;
|
|
|
|
|
unsigned int burst;
|
|
|
|
|
unsigned int num;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void ratelimit_init(struct ratelimit *r, uint64_t ival_ms, unsigned int burst);
|
|
|
|
|
enum ratelimit_state ratelimit_test(struct ratelimit *r);
|
|
|
|
|
|
2014-11-25 11:46:42 -06:00
|
|
|
int parse_mouse_dpi_property(const char *prop);
|
2015-01-12 08:39:47 +10:00
|
|
|
int parse_mouse_wheel_click_angle_property(const char *prop);
|
2016-10-28 15:08:32 +10:00
|
|
|
int parse_mouse_wheel_click_count_property(const char *prop);
|
2015-04-01 11:03:19 +02:00
|
|
|
double parse_trackpoint_accel_property(const char *prop);
|
2015-06-30 12:00:53 +10:00
|
|
|
bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
|
2017-02-09 10:25:50 +10:00
|
|
|
bool parse_calibration_property(const char *prop, float calibration[6]);
|
2017-07-05 16:25:40 +10:00
|
|
|
bool parse_range_property(const char *prop, int *hi, int *lo);
|
2017-06-28 13:09:22 +10:00
|
|
|
int parse_palm_pressure_property(const char *prop);
|
2017-03-23 14:54:00 +10:00
|
|
|
int parse_palm_size_property(const char *prop);
|
2018-05-24 09:52:17 +10:00
|
|
|
int parse_thumb_pressure_property(const char *prop);
|
2014-11-25 11:46:42 -06:00
|
|
|
|
2017-02-10 10:30:38 +10:00
|
|
|
enum tpkbcombo_layout {
|
|
|
|
|
TPKBCOMBO_LAYOUT_UNKNOWN,
|
|
|
|
|
TPKBCOMBO_LAYOUT_BELOW,
|
|
|
|
|
};
|
|
|
|
|
bool parse_tpkbcombo_layout_poperty(const char *prop,
|
|
|
|
|
enum tpkbcombo_layout *layout);
|
|
|
|
|
|
2017-01-25 13:24:31 +10:00
|
|
|
enum switch_reliability {
|
|
|
|
|
RELIABILITY_UNKNOWN,
|
|
|
|
|
RELIABILITY_RELIABLE,
|
2017-01-30 12:58:37 +10:00
|
|
|
RELIABILITY_WRITE_OPEN,
|
2017-01-25 13:24:31 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
parse_switch_reliability_property(const char *prop,
|
|
|
|
|
enum switch_reliability *reliability);
|
|
|
|
|
|
2015-07-27 17:51:52 +08:00
|
|
|
static inline uint64_t
|
|
|
|
|
us(uint64_t us)
|
|
|
|
|
{
|
|
|
|
|
return us;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline uint64_t
|
|
|
|
|
ns2us(uint64_t ns)
|
|
|
|
|
{
|
|
|
|
|
return us(ns / 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline uint64_t
|
|
|
|
|
ms2us(uint64_t ms)
|
|
|
|
|
{
|
|
|
|
|
return us(ms * 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline uint64_t
|
|
|
|
|
s2us(uint64_t s)
|
|
|
|
|
{
|
|
|
|
|
return ms2us(s * 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline uint32_t
|
|
|
|
|
us2ms(uint64_t us)
|
|
|
|
|
{
|
|
|
|
|
return (uint32_t)(us / 1000);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-26 08:56:29 +10:00
|
|
|
static inline uint64_t
|
|
|
|
|
tv2us(const struct timeval *tv)
|
|
|
|
|
{
|
|
|
|
|
return s2us(tv->tv_sec) + tv->tv_usec;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-22 11:33:19 +10:00
|
|
|
static inline struct timeval
|
|
|
|
|
us2tv(uint64_t time)
|
|
|
|
|
{
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
|
|
tv.tv_sec = time / ms2us(1000);
|
|
|
|
|
tv.tv_usec = time % ms2us(1000);
|
|
|
|
|
|
|
|
|
|
return tv;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-25 13:29:32 +10:00
|
|
|
static inline bool
|
2017-08-30 15:52:41 +10:00
|
|
|
safe_atoi_base(const char *str, int *val, int base)
|
2016-05-25 13:29:32 +10:00
|
|
|
{
|
2016-11-24 10:47:47 +10:00
|
|
|
char *endptr;
|
|
|
|
|
long v;
|
2016-05-25 13:29:32 +10:00
|
|
|
|
2017-08-30 15:52:41 +10:00
|
|
|
assert(base == 10 || base == 16 || base == 8);
|
|
|
|
|
|
2016-11-24 10:48:39 +10:00
|
|
|
errno = 0;
|
2017-08-30 15:52:41 +10:00
|
|
|
v = strtol(str, &endptr, base);
|
2016-11-24 10:48:39 +10:00
|
|
|
if (errno > 0)
|
|
|
|
|
return false;
|
2016-11-24 10:47:47 +10:00
|
|
|
if (str == endptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (*str != '\0' && *endptr != '\0')
|
|
|
|
|
return false;
|
2016-05-25 13:29:32 +10:00
|
|
|
|
2016-11-24 10:47:47 +10:00
|
|
|
if (v > INT_MAX || v < INT_MIN)
|
|
|
|
|
return false;
|
2016-05-25 13:29:32 +10:00
|
|
|
|
2016-11-24 10:47:47 +10:00
|
|
|
*val = v;
|
|
|
|
|
return true;
|
2016-05-25 13:29:32 +10:00
|
|
|
}
|
|
|
|
|
|
2017-08-30 15:52:41 +10:00
|
|
|
static inline bool
|
|
|
|
|
safe_atoi(const char *str, int *val)
|
|
|
|
|
{
|
|
|
|
|
return safe_atoi_base(str, val, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-01 10:21:18 +10:00
|
|
|
static inline bool
|
|
|
|
|
safe_atou_base(const char *str, unsigned int *val, int base)
|
|
|
|
|
{
|
|
|
|
|
char *endptr;
|
|
|
|
|
unsigned long v;
|
|
|
|
|
|
|
|
|
|
assert(base == 10 || base == 16 || base == 8);
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
v = strtoul(str, &endptr, base);
|
|
|
|
|
if (errno > 0)
|
|
|
|
|
return false;
|
|
|
|
|
if (str == endptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (*str != '\0' && *endptr != '\0')
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (v > UINT_MAX)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
*val = v;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
|
safe_atou(const char *str, unsigned int *val)
|
|
|
|
|
{
|
|
|
|
|
return safe_atou_base(str, val, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-24 10:51:26 +10:00
|
|
|
static inline bool
|
|
|
|
|
safe_atod(const char *str, double *val)
|
|
|
|
|
{
|
|
|
|
|
char *endptr;
|
|
|
|
|
double v;
|
|
|
|
|
locale_t c_locale;
|
|
|
|
|
|
|
|
|
|
/* Create a "C" locale to force strtod to use '.' as separator */
|
|
|
|
|
c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
|
|
|
|
|
if (c_locale == (locale_t)0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
v = strtod_l(str, &endptr, c_locale);
|
|
|
|
|
freelocale(c_locale);
|
|
|
|
|
if (errno > 0)
|
|
|
|
|
return false;
|
|
|
|
|
if (str == endptr)
|
|
|
|
|
return false;
|
|
|
|
|
if (*str != '\0' && *endptr != '\0')
|
|
|
|
|
return false;
|
|
|
|
|
if (isnan(v) || isinf(v))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
*val = v;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-25 16:12:10 +10:00
|
|
|
char **strv_from_string(const char *string, const char *separator);
|
2018-05-02 10:25:47 +10:00
|
|
|
char *strv_join(char **strv, const char *separator);
|
2016-11-25 16:12:10 +10:00
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
strv_free(char **strv) {
|
|
|
|
|
char **s = strv;
|
|
|
|
|
|
|
|
|
|
if (!strv)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
while (*s != NULL) {
|
|
|
|
|
free(*s);
|
|
|
|
|
*s = (char*)0x1; /* detect use-after-free */
|
|
|
|
|
s++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free (strv);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-11 17:51:44 +10:00
|
|
|
struct key_value_double {
|
|
|
|
|
double key;
|
|
|
|
|
double value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static inline ssize_t
|
|
|
|
|
kv_double_from_string(const char *string,
|
|
|
|
|
const char *pair_separator,
|
|
|
|
|
const char *kv_separator,
|
|
|
|
|
struct key_value_double **result_out)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
char **pairs;
|
|
|
|
|
char **pair;
|
|
|
|
|
struct key_value_double *result = NULL;
|
|
|
|
|
ssize_t npairs = 0;
|
|
|
|
|
unsigned int idx = 0;
|
|
|
|
|
|
|
|
|
|
if (!pair_separator || pair_separator[0] == '\0' ||
|
|
|
|
|
!kv_separator || kv_separator[0] == '\0')
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
pairs = strv_from_string(string, pair_separator);
|
|
|
|
|
if (!pairs)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
for (pair = pairs; *pair; pair++)
|
|
|
|
|
npairs++;
|
|
|
|
|
|
|
|
|
|
if (npairs == 0)
|
2018-05-11 15:02:26 +10:00
|
|
|
goto error;
|
2018-04-11 17:51:44 +10:00
|
|
|
|
|
|
|
|
result = zalloc(npairs * sizeof *result);
|
|
|
|
|
|
|
|
|
|
for (pair = pairs; *pair; pair++) {
|
|
|
|
|
char **kv = strv_from_string(*pair, kv_separator);
|
|
|
|
|
double k, v;
|
|
|
|
|
|
|
|
|
|
if (!kv || !kv[0] || !kv[1] || kv[2] ||
|
|
|
|
|
!safe_atod(kv[0], &k) ||
|
|
|
|
|
!safe_atod(kv[1], &v)) {
|
|
|
|
|
strv_free(kv);
|
|
|
|
|
goto error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result[idx].key = k;
|
|
|
|
|
result[idx].value = v;
|
|
|
|
|
idx++;
|
|
|
|
|
|
|
|
|
|
strv_free(kv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strv_free(pairs);
|
|
|
|
|
|
|
|
|
|
*result_out = result;
|
|
|
|
|
|
|
|
|
|
return npairs;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
strv_free(pairs);
|
|
|
|
|
free(result);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2013-11-17 11:19:50 +01:00
|
|
|
#endif /* LIBINPUT_UTIL_H */
|