1 /*
2  * Copyright 2014, Björn Ståhl
3  * License: 3-Clause BSD, see COPYING file in arcan source repository.
4  * Reference: http://arcan-fe.com
5  */
6 
7 /*
8  * This unit is rather ill-designed in that most things actually contain
9  * most things these days and the very idea of static databases vs. user-
10  * controlled typeset + calibration is terrible. Higher layers (e.g. Lua)
11  * mostly deals away with the notion outside the idevtype of a sample
12  * (i.e. digital, analog, touch) but it is still a mess.
13  *
14  * Most of the 'design' here should be viewed from a complete embedded
15  * platform where you can have a static tuning / calibration phase, and
16  * for the generic case, the keyboard/game/touch separation is usually
17  * 'good enough'..
18  */
19 enum devnode_type {
20 	DEVNODE_KEYBOARD = 0,
21 	DEVNODE_MOUSE,
22 	DEVNODE_GAME,
23 	DEVNODE_TOUCH,
24 	DEVNODE_SENSOR,
25 	DEVNODE_SWITCH,
26 	DEVNODE_MISSING
27 };
28 
29 typedef void (*devnode_decode_cb)(struct arcan_evctx*, struct devnode*);
30 
31 struct evhandler {
32 	const char* name;
33 	enum devnode_type type;
34 	devnode_decode_cb handler;
35 
36 /*
37  * (not used by all subtypes)
38  * if corresponding bit is set for axis_mask or button_mask vs.
39  * event-code, the event will be dropped. It can be used to get rid of
40  * specific axis values for broken devices that spam events or are stuck.
41  */
42 	uint64_t axis_mask;
43 	uint64_t button_mask;
44 };
45 
46 static void defhandler_kbd(struct arcan_evctx*, struct devnode*);
47 static void defhandler_mouse(struct arcan_evctx*, struct devnode*);
48 static void defhandler_game(struct arcan_evctx*, struct devnode*);
49 static void defhandler_null(struct arcan_evctx*, struct devnode*);
50 
51 /* as with the other input.c, we should probably just move this out into
52  * the virtual filesystem and have the path indicate decoder type as this
53  * will just get worse and worse. See these entries as examples :-) */
54 static struct evhandler device_db[] = {
55 	{
56 	.name = "Microsoft X-Box 360 pad",
57 	.type = DEVNODE_GAME,
58 	.handler = defhandler_game,
59 	},
60 	{
61 	.name = "ckb1",
62 	.type = DEVNODE_KEYBOARD,
63 	.handler = defhandler_kbd
64 	}
65 };
66 
67 /*
68  * matching devnode_type enum, this is somewhat of a misnomer in that device
69  * detection can often just resolve to the first three types and especially
70  * gamedev because the range available today covers pretty much everything
71  */
72 static devnode_decode_cb defhandlers[] = {
73 	defhandler_kbd,
74 	defhandler_mouse,
75 	defhandler_game,
76 	defhandler_null,
77 	defhandler_null,
78 	defhandler_null,
79 	defhandler_null
80 };
81 
lookup_dev_handler(const char * idstr)82 static struct evhandler lookup_dev_handler(const char* idstr)
83 {
84 /* enumerate key */
85 	uintptr_t tag;
86 	cfg_lookup_fun get_config = platform_config_lookup(&tag);
87 	char* dst;
88 	unsigned short ind = 0;
89 
90 	while (get_config("evdev_keyboard", ind++, &dst, tag)){
91 		if (strcasecmp(dst, idstr) == 0){
92 			free(dst);
93 /* mapping the idstr is safe here as it is tied to the lifespan
94  * of the node it will be used for and not separately allocated */
95 			return (struct evhandler){
96 				.handler = defhandler_kbd,
97 				.type = DEVNODE_KEYBOARD,
98 				.name = idstr
99 			};
100 		}
101 		free(dst);
102 	}
103 
104 	ind = 0;
105 	while (get_config("evdev_mouse", ind++, &dst, tag)){
106 		if (strcasecmp(dst, idstr) == 0){
107 			free(dst);
108 			return (struct evhandler){
109 				.handler = defhandler_mouse,
110 				.type = DEVNODE_MOUSE,
111 				.name = idstr
112 			};
113 		}
114 		free(dst);
115 	}
116 
117 	ind = 0;
118 	while (get_config("evdev_game", ind++, &dst, tag)){
119 		if (strcasecmp(dst, idstr) == 0){
120 			free(dst);
121 			return (struct evhandler){
122 				.handler = defhandler_game,
123 				.type = DEVNODE_GAME,
124 				.name = idstr
125 			};
126 		}
127 		free(dst);
128 	}
129 
130 	for (size_t ind = 0; ind < sizeof(device_db)/sizeof(device_db[0]); ind++){
131 		if (strcmp(idstr, device_db[ind].name) == 0)
132 			return device_db[ind];
133 	}
134 
135 #ifdef ARCAN_EVENT_WHITELIST
136 	struct evhandler def = {
137 		.name = "whitelist",
138 		.type = DEVNODE_MISSING,
139 		.handler = defhandler_null
140 	};
141 #else
142 	struct evhandler def = {0};
143 #endif
144 
145 	return def;
146 }
147