diff --git a/Makefile b/Makefile index f3a0978..6978851 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ CPPFLAGS += $(shell pkg-config --cflags $(DEPS)) LDLIBS += $(shell pkg-config --libs $(DEPS)) INTERP ?= MAIN = main -OBJS = main.o events.o processing.o graph.o config.o event_code_names.o hash_table.o queue.o module_registry.o event_predicate.o nodes/getchar.o nodes/print.o nodes/evdev.o nodes/tee.o nodes/router.o nodes/modifiers.o nodes/modify_predicate.o nodes/uinput.o nodes/assign.o nodes/differentiate.o nodes/scale.o nodes/window.o +OBJS = main.o events.o processing.o graph.o config.o event_code_names.o hash_table.o queue.o module_registry.o event_predicate.o nodes/getchar.o nodes/print.o nodes/evdev.o nodes/tee.o nodes/router.o nodes/modifiers.o nodes/modify_predicate.o nodes/uinput.o nodes/assign.o nodes/differentiate.o nodes/integrate.o nodes/scale.o nodes/window.o all: $(MAIN) diff --git a/config.cfg b/config.cfg index 929dcc3..e3506ae 100644 --- a/config.cfg +++ b/config.cfg @@ -3,7 +3,8 @@ constants = { }; enums = { - namespaces: ["stdin", "clickpad"]; + namespaces: ["stdin", "clickpad", "variable"]; + variables: ["num_touches"]; }; predicates = { @@ -23,6 +24,17 @@ predicates = { } ); }; + abs_event = { + type = "and"; + args = ( + "is_evdev", + { + type = "code_major"; + min = "event_type.ABS"; + max = "event_type.ABS"; + } + ); + }; btn_touch_event = { type = "and"; args = ( @@ -34,6 +46,17 @@ predicates = { } ); }; + touch_tracking_id = { + type = "and"; + args = ( + "abs_event", + { + type = "code_minor"; + min = "absolute_axis.MT_TRACKING_ID"; + max = "absolute_axis.MT_TRACKING_ID"; + } + ); + }; payload_zero = { type = "payload"; min = 0; @@ -44,6 +67,22 @@ predicates = { min = 1; max = 1; }; + payload_negative = { + type = "payload"; + max = -1; + }; + payload_nonnegative = { + type = "payload"; + min = 0; + }; + touch_start = { + type = "and"; + args = ["touch_tracking_id", "payload_nonnegative"]; + }; + touch_end = { + type = "and"; + args = ["touch_tracking_id", "payload_negative"]; + }; touch_held = { type = "accept"; inverted = 1; @@ -78,7 +117,9 @@ nodes = { type = "or"; inverted = 1; args = ["key_event"]; - } + }, + "touch_start", + "touch_end" ); }; }; @@ -116,6 +157,24 @@ nodes = { ); }; }; + set_one = { + type = "assign"; + options = { + payload = 1; + }; + }; + count_touches = { + // This exact usecase may be implemented using events like button_event.TOOL_DOUBLETAP, button_event.TOOL_TRIPLETAP, button_event.TOOL_QUADTAP, button_event.TOOL_QUINTTAP + type = "integrate"; + }; + set_variable_num_touches = { + type = "assign"; + options = { + namespace = "namespaces.variable"; + major = "variables.num_touches"; + minor = 0; + }; + }; }; channels = ({ @@ -139,6 +198,21 @@ channels = ({ }, { from: ("clickpad", 1); to: ("update_touch_held", 0); +}, { + from: ("select_key_events", 2); // touch_start + to: ("set_one", 0); +}, { + from: ("set_one", 0); + to: ("count_touches", 0); +}, { + from: ("select_key_events", 3); // touch_end + to: ("count_touches", 1); +}, { + from: ("count_touches", 0); + to: ("set_variable_num_touches", 0); +}, { + from: ("set_variable_num_touches", 0); + to: ("print", 2); }); // vim: ft=libconfig diff --git a/nodes/integrate.c b/nodes/integrate.c new file mode 100644 index 0000000..8634269 --- /dev/null +++ b/nodes/integrate.c @@ -0,0 +1,78 @@ +#include "../graph.h" +#include "../module_registry.h" + +typedef struct { + GraphNode as_GraphNode; + int64_t total; +} IntegrateGraphNode; + +static bool +handle_event(EventPositionBase * self, EventNode * event) +{ + IntegrateGraphNode *node = DOWNCAST(IntegrateGraphNode, GraphNode, DOWNCAST(GraphNode, EventPositionBase, self)); + size_t count = node->as_GraphNode.outputs.length; + if (!count) { + event_destroy(event); + return true; + } + + int64_t total = node->total; + total += event->data.payload; + event->data.payload = total; + node->total = total; + + graph_node_broadcast_forward_event(&node->as_GraphNode, event); + return true; +} + +static GraphNode * +create(GraphNodeSpecification * spec, GraphNodeConfig * config, InitializationEnvironment * env) +{ + (void) config; + (void) env; + IntegrateGraphNode * node = T_ALLOC(1, IntegrateGraphNode); + if (!node) { + return NULL; + } + + int64_t initial = 0; + if (config->options) { + initial = env_resolve_constant(env, config_setting_get_member(config->options, "initial")); + } + + *node = (IntegrateGraphNode) { + .as_GraphNode = { + .as_EventPositionBase = { + .handle_event = &handle_event, + .waiting_new_event = false, + }, + .specification = spec, + .inputs = EMPTY_GRAPH_CHANNEL_LIST, + .outputs = EMPTY_GRAPH_CHANNEL_LIST, + }, + .total = initial, + }; + return &node->as_GraphNode; +} + +static void destroy +(GraphNodeSpecification * self, GraphNode * target) +{ + (void) self; + free(target); +} + +GraphNodeSpecification nodespec_integrate = (GraphNodeSpecification) { + .create = &create, + .destroy = &destroy, + .register_io = NULL, + .name = "integrate", + .documentation = "Calculates a running sum of previous event payloads and replaces with it the current one\nAccepts events on any connector\nSends events on all connectors" + "\nOption 'initial' (optional): the initial partial sum value" + , +}; + +MODULE_CONSTRUCTOR(init) +{ + register_graph_node_specification(&nodespec_integrate); +}