diff options
-rw-r--r-- | CMake/FindLibInput.cmake | 66 | ||||
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | include/commands.h | 3 | ||||
-rw-r--r-- | include/config.h | 28 | ||||
-rw-r--r-- | include/input.h | 23 | ||||
-rw-r--r-- | include/ipc.h | 6 | ||||
-rw-r--r-- | sway/CMakeLists.txt | 3 | ||||
-rw-r--r-- | sway/commands.c | 312 | ||||
-rw-r--r-- | sway/config.c | 116 | ||||
-rw-r--r-- | sway/handlers.c | 38 | ||||
-rw-r--r-- | sway/input.c | 54 | ||||
-rw-r--r-- | sway/ipc-server.c | 20 | ||||
-rw-r--r-- | sway/main.c | 7 | ||||
-rw-r--r-- | sway/sway-input.5.txt | 46 | ||||
-rw-r--r-- | swaymsg/main.c | 2 | ||||
-rw-r--r-- | swaymsg/swaymsg.1.txt | 3 |
16 files changed, 727 insertions, 3 deletions
diff --git a/CMake/FindLibInput.cmake b/CMake/FindLibInput.cmake new file mode 100644 index 00000000..87721998 --- /dev/null +++ b/CMake/FindLibInput.cmake | |||
@@ -0,0 +1,66 @@ | |||
1 | #.rst: | ||
2 | # FindLibInput | ||
3 | # ------- | ||
4 | # | ||
5 | # Find LibInput library | ||
6 | # | ||
7 | # Try to find LibInpu library. The following values are defined | ||
8 | # | ||
9 | # :: | ||
10 | # | ||
11 | # LIBINPUT_FOUND - True if libinput is available | ||
12 | # LIBINPUT_INCLUDE_DIRS - Include directories for libinput | ||
13 | # LIBINPUT_LIBRARIES - List of libraries for libinput | ||
14 | # LIBINPUT_DEFINITIONS - List of definitions for libinput | ||
15 | # | ||
16 | # and also the following more fine grained variables | ||
17 | # | ||
18 | # :: | ||
19 | # | ||
20 | # LIBINPUT_VERSION | ||
21 | # LIBINPUT_VERSION_MAJOR | ||
22 | # LIBINPUT_VERSION_MINOR | ||
23 | # LIBINPUT_VERSION_MICRO | ||
24 | # | ||
25 | #============================================================================= | ||
26 | # Copyright (c) 2015 Jari Vetoniemi | ||
27 | # | ||
28 | # Distributed under the OSI-approved BSD License (the "License"); | ||
29 | # | ||
30 | # This software is distributed WITHOUT ANY WARRANTY; without even the | ||
31 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
32 | # See the License for more information. | ||
33 | #============================================================================= | ||
34 | |||
35 | include(FeatureSummary) | ||
36 | set_package_properties(LibInput PROPERTIES | ||
37 | URL "http://freedesktop.org/wiki/Software/libinput/" | ||
38 | DESCRIPTION "Library to handle input devices") | ||
39 | |||
40 | find_package(PkgConfig) | ||
41 | pkg_check_modules(PC_INPUT QUIET libinput) | ||
42 | find_library(LIBINPUT_LIBRARIES NAMES input HINTS ${PC_INPUT_LIBRARY_DIRS}) | ||
43 | find_path(LIBINPUT_INCLUDE_DIRS libinput.h HINTS ${PC_INPUT_INCLUDE_DIRS}) | ||
44 | |||
45 | set(LIBINPUT_VERSION ${PC_INPUT_VERSION}) | ||
46 | string(REPLACE "." ";" VERSION_LIST "${PC_INPUT_VERSION}") | ||
47 | |||
48 | LIST(LENGTH VERSION_LIST n) | ||
49 | if (n EQUAL 3) | ||
50 | list(GET VERSION_LIST 0 LIBINPUT_VERSION_MAJOR) | ||
51 | list(GET VERSION_LIST 1 LIBINPUT_VERSION_MINOR) | ||
52 | list(GET VERSION_LIST 2 LIBINPUT_VERSION_MICRO) | ||
53 | endif () | ||
54 | |||
55 | # This is compatible with libinput-version.h that exists in upstream | ||
56 | # but isn't in distribution (probably forgotten) | ||
57 | set(LIBINPUT_DEFINITIONS ${PC_INPUT_CFLAGS_OTHER} | ||
58 | -DLIBINPUT_VERSION=\"${LIBINPUT_VERSION}\" | ||
59 | -DLIBINPUT_VERSION_MAJOR=${LIBINPUT_VERSION_MAJOR} | ||
60 | -DLIBINPUT_VERSION_MINOR=${LIBINPUT_VERSION_MINOR} | ||
61 | -DLIBINPUT_VERSION_MICRO=${LIBINPUT_VERSION_MICRO}) | ||
62 | |||
63 | include(FindPackageHandleStandardArgs) | ||
64 | find_package_handle_standard_args(LIBINPUT DEFAULT_MSG LIBINPUT_INCLUDE_DIRS LIBINPUT_LIBRARIES) | ||
65 | mark_as_advanced(LIBINPUT_INCLUDE_DIRS LIBINPUT_LIBRARIES LIBINPUT_DEFINITIONS | ||
66 | LIBINPUT_VERSION LIBINPUT_VERSION_MAJOR LIBINPUT_VERSION_MICRO LIBINPUT_VERSION_MINOR) | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index 587c3dac..4620ff54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -57,6 +57,9 @@ find_package(Pango) | |||
57 | find_package(GdkPixbuf) | 57 | find_package(GdkPixbuf) |
58 | find_package(PAM) | 58 | find_package(PAM) |
59 | 59 | ||
60 | find_package(LibInput REQUIRED) | ||
61 | include_directories(${LIBINPUT_INClUDE_DIRS}) | ||
62 | |||
60 | find_package(Backtrace) | 63 | find_package(Backtrace) |
61 | if(Backtrace_FOUND) | 64 | if(Backtrace_FOUND) |
62 | include_directories("${Backtrace_INCLUDE_DIRS}") | 65 | include_directories("${Backtrace_INCLUDE_DIRS}") |
diff --git a/include/commands.h b/include/commands.h index 52d56e4a..5fa66bb6 100644 --- a/include/commands.h +++ b/include/commands.h | |||
@@ -17,7 +17,8 @@ enum cmd_status { | |||
17 | CMD_BLOCK_END, | 17 | CMD_BLOCK_END, |
18 | CMD_BLOCK_MODE, | 18 | CMD_BLOCK_MODE, |
19 | CMD_BLOCK_BAR, | 19 | CMD_BLOCK_BAR, |
20 | CMD_BLOCK_BAR_COLORS | 20 | CMD_BLOCK_BAR_COLORS, |
21 | CMD_BLOCK_INPUT | ||
21 | }; | 22 | }; |
22 | 23 | ||
23 | /** | 24 | /** |
diff --git a/include/config.h b/include/config.h index e6a85b29..c2b67aa6 100644 --- a/include/config.h +++ b/include/config.h | |||
@@ -1,7 +1,9 @@ | |||
1 | #ifndef _SWAY_CONFIG_H | 1 | #ifndef _SWAY_CONFIG_H |
2 | #define _SWAY_CONFIG_H | 2 | #define _SWAY_CONFIG_H |
3 | 3 | ||
4 | #include <libinput.h> | ||
4 | #include <stdint.h> | 5 | #include <stdint.h> |
6 | #include <wlc/geometry.h> | ||
5 | #include <wlc/wlc.h> | 7 | #include <wlc/wlc.h> |
6 | #include <xkbcommon/xkbcommon.h> | 8 | #include <xkbcommon/xkbcommon.h> |
7 | #include "wayland-desktop-shell-server-protocol.h" | 9 | #include "wayland-desktop-shell-server-protocol.h" |
@@ -46,6 +48,25 @@ struct sway_mode { | |||
46 | }; | 48 | }; |
47 | 49 | ||
48 | /** | 50 | /** |
51 | * libinput options for input devices | ||
52 | */ | ||
53 | struct input_config { | ||
54 | char *identifier; | ||
55 | int click_method; | ||
56 | int drag_lock; | ||
57 | int dwt; | ||
58 | int middle_emulation; | ||
59 | int natural_scroll; | ||
60 | float pointer_accel; | ||
61 | int scroll_method; | ||
62 | int send_events; | ||
63 | int tap; | ||
64 | |||
65 | bool capturable; | ||
66 | struct wlc_geometry region; | ||
67 | }; | ||
68 | |||
69 | /** | ||
49 | * Size and position configuration for a particular output. | 70 | * Size and position configuration for a particular output. |
50 | * | 71 | * |
51 | * This is set via the `output` command. | 72 | * This is set via the `output` command. |
@@ -136,6 +157,7 @@ struct sway_config { | |||
136 | list_t *cmd_queue; | 157 | list_t *cmd_queue; |
137 | list_t *workspace_outputs; | 158 | list_t *workspace_outputs; |
138 | list_t *output_configs; | 159 | list_t *output_configs; |
160 | list_t *input_configs; | ||
139 | list_t *criteria; | 161 | list_t *criteria; |
140 | list_t *active_bar_modifiers; | 162 | list_t *active_bar_modifiers; |
141 | struct sway_mode *current_mode; | 163 | struct sway_mode *current_mode; |
@@ -172,6 +194,12 @@ bool read_config(FILE *file, bool is_active); | |||
172 | * Does variable replacement for a string based on the config's currently loaded variables. | 194 | * Does variable replacement for a string based on the config's currently loaded variables. |
173 | */ | 195 | */ |
174 | char *do_var_replacement(char *str); | 196 | char *do_var_replacement(char *str); |
197 | |||
198 | int input_identifier_cmp(const void *item, const void *data); | ||
199 | void merge_input_config(struct input_config *dst, struct input_config *src); | ||
200 | void apply_input_config(struct input_config *ic, struct libinput_device *dev); | ||
201 | void free_input_config(struct input_config *ic); | ||
202 | |||
175 | int output_name_cmp(const void *item, const void *data); | 203 | int output_name_cmp(const void *item, const void *data); |
176 | void merge_output_config(struct output_config *dst, struct output_config *src); | 204 | void merge_output_config(struct output_config *dst, struct output_config *src); |
177 | /** Sets up a WLC output handle based on a given output_config. | 205 | /** Sets up a WLC output handle based on a given output_config. |
diff --git a/include/input.h b/include/input.h new file mode 100644 index 00000000..4ed9bffe --- /dev/null +++ b/include/input.h | |||
@@ -0,0 +1,23 @@ | |||
1 | #ifndef _SWAY_INPUT_H | ||
2 | #define _SWAY_INPUT_H | ||
3 | |||
4 | #include <libinput.h> | ||
5 | #include "config.h" | ||
6 | #include "list.h" | ||
7 | |||
8 | struct input_config *new_input_config(const char* identifier); | ||
9 | |||
10 | char* libinput_dev_unique_id(struct libinput_device *dev); | ||
11 | |||
12 | /** | ||
13 | * Global input device list. | ||
14 | */ | ||
15 | extern list_t *input_devices; | ||
16 | |||
17 | /** | ||
18 | * Pointer used when reading input blocked. | ||
19 | * Shared so that it can be cleared from commands.c when closing the block | ||
20 | */ | ||
21 | extern struct input_config *current_input_config; | ||
22 | |||
23 | #endif | ||
diff --git a/include/ipc.h b/include/ipc.h index 56593529..934049c2 100644 --- a/include/ipc.h +++ b/include/ipc.h | |||
@@ -5,11 +5,12 @@ enum ipc_command_type { | |||
5 | IPC_COMMAND = 0, | 5 | IPC_COMMAND = 0, |
6 | IPC_GET_WORKSPACES = 1, | 6 | IPC_GET_WORKSPACES = 1, |
7 | IPC_SUBSCRIBE = 2, | 7 | IPC_SUBSCRIBE = 2, |
8 | IPC_GET_OUTPUTS = 3, | 8 | IPC_GET_OUTPUTS = 3, |
9 | IPC_GET_TREE = 4, | 9 | IPC_GET_TREE = 4, |
10 | IPC_GET_MARKS = 5, | 10 | IPC_GET_MARKS = 5, |
11 | IPC_GET_BAR_CONFIG = 6, | 11 | IPC_GET_BAR_CONFIG = 6, |
12 | IPC_GET_VERSION = 7, | 12 | IPC_GET_VERSION = 7, |
13 | IPC_GET_INPUTS = 8, | ||
13 | // Events send from sway to clients. Events have the higest bit set. | 14 | // Events send from sway to clients. Events have the higest bit set. |
14 | IPC_EVENT_WORKSPACE = (1 << 31 | 0), | 15 | IPC_EVENT_WORKSPACE = (1 << 31 | 0), |
15 | IPC_EVENT_OUTPUT = (1 << 31 | 1), | 16 | IPC_EVENT_OUTPUT = (1 << 31 | 1), |
@@ -18,6 +19,7 @@ enum ipc_command_type { | |||
18 | IPC_EVENT_BARCONFIG_UPDATE = (1 << 31 | 4), | 19 | IPC_EVENT_BARCONFIG_UPDATE = (1 << 31 | 4), |
19 | IPC_EVENT_BINDING = (1 << 31 | 5), | 20 | IPC_EVENT_BINDING = (1 << 31 | 5), |
20 | IPC_EVENT_MODIFIER = (1 << 31 | 6), | 21 | IPC_EVENT_MODIFIER = (1 << 31 | 6), |
22 | IPC_EVENT_INPUT = (1 << 31 | 7), | ||
21 | IPC_SWAY_GET_PIXELS = 0x81 | 23 | IPC_SWAY_GET_PIXELS = 0x81 |
22 | }; | 24 | }; |
23 | 25 | ||
diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt index 23829dc3..f7cc88ab 100644 --- a/sway/CMakeLists.txt +++ b/sway/CMakeLists.txt | |||
@@ -4,6 +4,7 @@ include_directories( | |||
4 | ${PCRE_INCLUDE_DIRS} | 4 | ${PCRE_INCLUDE_DIRS} |
5 | ${JSONC_INCLUDE_DIRS} | 5 | ${JSONC_INCLUDE_DIRS} |
6 | ${XKBCOMMON_INCLUDE_DIRS} | 6 | ${XKBCOMMON_INCLUDE_DIRS} |
7 | ${LIBINPUT_LIBRARIES} | ||
7 | ) | 8 | ) |
8 | 9 | ||
9 | add_executable(sway | 10 | add_executable(sway |
@@ -15,6 +16,7 @@ add_executable(sway | |||
15 | extensions.c | 16 | extensions.c |
16 | focus.c | 17 | focus.c |
17 | handlers.c | 18 | handlers.c |
19 | input.c | ||
18 | input_state.c | 20 | input_state.c |
19 | ipc-server.c | 21 | ipc-server.c |
20 | layout.c | 22 | layout.c |
@@ -32,6 +34,7 @@ target_link_libraries(sway | |||
32 | ${PCRE_LIBRARIES} | 34 | ${PCRE_LIBRARIES} |
33 | ${JSONC_LIBRARIES} | 35 | ${JSONC_LIBRARIES} |
34 | ${WAYLAND_SERVER_LIBRARIES} | 36 | ${WAYLAND_SERVER_LIBRARIES} |
37 | ${LIBINPUT_LIBRARIES} | ||
35 | m | 38 | m |
36 | ) | 39 | ) |
37 | 40 | ||
diff --git a/sway/commands.c b/sway/commands.c index 1c7eb962..5c8653ed 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -11,6 +11,9 @@ | |||
11 | #include <wordexp.h> | 11 | #include <wordexp.h> |
12 | #include <sys/types.h> | 12 | #include <sys/types.h> |
13 | #include <sys/wait.h> | 13 | #include <sys/wait.h> |
14 | #include <limits.h> | ||
15 | #include <float.h> | ||
16 | #include <libinput.h> | ||
14 | #include "stringop.h" | 17 | #include "stringop.h" |
15 | #include "layout.h" | 18 | #include "layout.h" |
16 | #include "focus.h" | 19 | #include "focus.h" |
@@ -26,6 +29,8 @@ | |||
26 | #include "input_state.h" | 29 | #include "input_state.h" |
27 | #include "criteria.h" | 30 | #include "criteria.h" |
28 | #include "ipc-server.h" | 31 | #include "ipc-server.h" |
32 | #include "list.h" | ||
33 | #include "input.h" | ||
29 | 34 | ||
30 | typedef struct cmd_results *sway_cmd(int argc, char **argv); | 35 | typedef struct cmd_results *sway_cmd(int argc, char **argv); |
31 | 36 | ||
@@ -49,6 +54,7 @@ static sway_cmd cmd_focus_follows_mouse; | |||
49 | static sway_cmd cmd_for_window; | 54 | static sway_cmd cmd_for_window; |
50 | static sway_cmd cmd_fullscreen; | 55 | static sway_cmd cmd_fullscreen; |
51 | static sway_cmd cmd_gaps; | 56 | static sway_cmd cmd_gaps; |
57 | static sway_cmd cmd_input; | ||
52 | static sway_cmd cmd_kill; | 58 | static sway_cmd cmd_kill; |
53 | static sway_cmd cmd_layout; | 59 | static sway_cmd cmd_layout; |
54 | static sway_cmd cmd_log_colors; | 60 | static sway_cmd cmd_log_colors; |
@@ -866,6 +872,293 @@ static struct cmd_results *cmd_orientation(int argc, char **argv) { | |||
866 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 872 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
867 | } | 873 | } |
868 | 874 | ||
875 | static void input_cmd_apply(struct input_config *input) { | ||
876 | int i; | ||
877 | i = list_seq_find(config->input_configs, input_identifier_cmp, input->identifier); | ||
878 | if (i >= 0) { | ||
879 | // merge existing config | ||
880 | struct input_config *ic = config->input_configs->items[i]; | ||
881 | merge_input_config(ic, input); | ||
882 | free_input_config(input); | ||
883 | input = ic; | ||
884 | } else { | ||
885 | list_add(config->input_configs, input); | ||
886 | } | ||
887 | |||
888 | current_input_config = input; | ||
889 | |||
890 | if (input->identifier) { | ||
891 | // Try to find the input device and apply configuration now. If | ||
892 | // this is during startup then there will be no container and config | ||
893 | // will be applied during normal "new input" event from wlc. | ||
894 | struct libinput_device *device = NULL; | ||
895 | for (int i = 0; i < input_devices->length; ++i) { | ||
896 | device = input_devices->items[i]; | ||
897 | char* dev_identifier = libinput_dev_unique_id(device); | ||
898 | int match = dev_identifier && strcmp(dev_identifier, input->identifier) == 0; | ||
899 | free(dev_identifier); | ||
900 | if (match) { | ||
901 | apply_input_config(input, device); | ||
902 | break; | ||
903 | } | ||
904 | } | ||
905 | } | ||
906 | } | ||
907 | |||
908 | static struct cmd_results *input_cmd_click_method(int argc, char **argv) { | ||
909 | sway_log(L_DEBUG, "click_method for device: %d %s", current_input_config==NULL, current_input_config->identifier); | ||
910 | struct cmd_results *error = NULL; | ||
911 | if ((error = checkarg(argc, "click_method", EXPECTED_AT_LEAST, 1))) { | ||
912 | return error; | ||
913 | } | ||
914 | if (!current_input_config) { | ||
915 | return cmd_results_new(CMD_FAILURE, "click_method", "No input device defined."); | ||
916 | } | ||
917 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
918 | |||
919 | if (strcasecmp(argv[0], "none") == 0) { | ||
920 | new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; | ||
921 | } else if (strcasecmp(argv[0], "button_areas") == 0) { | ||
922 | new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; | ||
923 | } else if (strcasecmp(argv[0], "clickfinger") == 0) { | ||
924 | new_config->click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; | ||
925 | } else { | ||
926 | return cmd_results_new(CMD_INVALID, "click_method", "Expected 'click_method <none|button_areas|clickfinger'"); | ||
927 | } | ||
928 | |||
929 | input_cmd_apply(new_config); | ||
930 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
931 | } | ||
932 | |||
933 | static struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { | ||
934 | struct cmd_results *error = NULL; | ||
935 | if ((error = checkarg(argc, "drag_lock", EXPECTED_AT_LEAST, 1))) { | ||
936 | return error; | ||
937 | } | ||
938 | if (!current_input_config) { | ||
939 | return cmd_results_new(CMD_FAILURE, "drag_lock", "No input device defined."); | ||
940 | } | ||
941 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
942 | |||
943 | if (strcasecmp(argv[0], "enabled") == 0) { | ||
944 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; | ||
945 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
946 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; | ||
947 | } else { | ||
948 | return cmd_results_new(CMD_INVALID, "drag_lock", "Expected 'drag_lock <enabled|disabled>'"); | ||
949 | } | ||
950 | |||
951 | input_cmd_apply(new_config); | ||
952 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
953 | } | ||
954 | |||
955 | static struct cmd_results *input_cmd_dwt(int argc, char **argv) { | ||
956 | struct cmd_results *error = NULL; | ||
957 | if ((error = checkarg(argc, "dwt", EXPECTED_AT_LEAST, 1))) { | ||
958 | return error; | ||
959 | } | ||
960 | if (!current_input_config) { | ||
961 | return cmd_results_new(CMD_FAILURE, "dwt", "No input device defined."); | ||
962 | } | ||
963 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
964 | |||
965 | if (strcasecmp(argv[0], "enabled") == 0) { | ||
966 | new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; | ||
967 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
968 | new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; | ||
969 | } else { | ||
970 | return cmd_results_new(CMD_INVALID, "dwt", "Expected 'dwt <enabled|disabled>'"); | ||
971 | } | ||
972 | |||
973 | input_cmd_apply(new_config); | ||
974 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
975 | } | ||
976 | |||
977 | static struct cmd_results *input_cmd_events(int argc, char **argv) { | ||
978 | sway_log(L_DEBUG, "events for device: %s", current_input_config->identifier); | ||
979 | struct cmd_results *error = NULL; | ||
980 | if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) { | ||
981 | return error; | ||
982 | } | ||
983 | if (!current_input_config) { | ||
984 | return cmd_results_new(CMD_FAILURE, "events", "No input device defined."); | ||
985 | } | ||
986 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
987 | |||
988 | if (strcasecmp(argv[0], "enabled") == 0) { | ||
989 | new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; | ||
990 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
991 | new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; | ||
992 | } else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) { | ||
993 | new_config->send_events = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; | ||
994 | } else { | ||
995 | return cmd_results_new(CMD_INVALID, "events", "Expected 'events <enabled|disabled|disabled_on_external_mouse>'"); | ||
996 | } | ||
997 | |||
998 | input_cmd_apply(new_config); | ||
999 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
1000 | } | ||
1001 | |||
1002 | static struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { | ||
1003 | struct cmd_results *error = NULL; | ||
1004 | if ((error = checkarg(argc, "middle_emulation", EXPECTED_AT_LEAST, 1))) { | ||
1005 | return error; | ||
1006 | } | ||
1007 | if (!current_input_config) { | ||
1008 | return cmd_results_new(CMD_FAILURE, "middle_emulation", "No input device defined."); | ||
1009 | } | ||
1010 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
1011 | |||
1012 | if (strcasecmp(argv[0], "enabled") == 0) { | ||
1013 | new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; | ||
1014 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
1015 | new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; | ||
1016 | } else { | ||
1017 | return cmd_results_new(CMD_INVALID, "middle_emulation", "Expected 'middle_emulation <enabled|disabled>'"); | ||
1018 | } | ||
1019 | |||
1020 | input_cmd_apply(new_config); | ||
1021 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
1022 | } | ||
1023 | |||
1024 | static struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { | ||
1025 | struct cmd_results *error = NULL; | ||
1026 | if ((error = checkarg(argc, "natural_scroll", EXPECTED_AT_LEAST, 1))) { | ||
1027 | return error; | ||
1028 | } | ||
1029 | if (!current_input_config) { | ||
1030 | return cmd_results_new(CMD_FAILURE, "natural_scoll", "No input device defined."); | ||
1031 | } | ||
1032 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
1033 | |||
1034 | if (strcasecmp(argv[0], "enabled") == 0) { | ||
1035 | new_config->natural_scroll = 1; | ||
1036 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
1037 | new_config->natural_scroll = 0; | ||
1038 | } else { | ||
1039 | return cmd_results_new(CMD_INVALID, "natural_scroll", "Expected 'natural_scroll <enabled|disabled>'"); | ||
1040 | } | ||
1041 | |||
1042 | input_cmd_apply(new_config); | ||
1043 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
1044 | } | ||
1045 | |||
1046 | static struct cmd_results *input_cmd_pointer_accel(int argc, char **argv) { | ||
1047 | struct cmd_results *error = NULL; | ||
1048 | if ((error = checkarg(argc, "pointer_accel", EXPECTED_AT_LEAST, 1))) { | ||
1049 | return error; | ||
1050 | } | ||
1051 | if (!current_input_config) { | ||
1052 | return cmd_results_new(CMD_FAILURE, "pointer_accel", "No input device defined."); | ||
1053 | } | ||
1054 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
1055 | |||
1056 | float pointer_accel = atof(argv[0]); | ||
1057 | if (pointer_accel < -1 || pointer_accel > 1) { | ||
1058 | return cmd_results_new(CMD_INVALID, "pointer_accel", "Input out of range [-1, 1]"); | ||
1059 | } | ||
1060 | new_config->pointer_accel = pointer_accel; | ||
1061 | |||
1062 | input_cmd_apply(new_config); | ||
1063 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
1064 | } | ||
1065 | |||
1066 | static struct cmd_results *input_cmd_scroll_method(int argc, char **argv) { | ||
1067 | struct cmd_results *error = NULL; | ||
1068 | if ((error = checkarg(argc, "scroll_method", EXPECTED_AT_LEAST, 1))) { | ||
1069 | return error; | ||
1070 | } | ||
1071 | if (!current_input_config) { | ||
1072 | return cmd_results_new(CMD_FAILURE, "scroll_method", "No input device defined."); | ||
1073 | } | ||
1074 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
1075 | |||
1076 | if (strcasecmp(argv[0], "none") == 0) { | ||
1077 | new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; | ||
1078 | } else if (strcasecmp(argv[0], "two_finger") == 0) { | ||
1079 | new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; | ||
1080 | } else if (strcasecmp(argv[0], "edge") == 0) { | ||
1081 | new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_EDGE; | ||
1082 | } else if (strcasecmp(argv[0], "on_button_down") == 0) { | ||
1083 | new_config->scroll_method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; | ||
1084 | } else { | ||
1085 | return cmd_results_new(CMD_INVALID, "scroll_method", "Expected 'scroll_method <none|two_finger|edge|on_button_down>'"); | ||
1086 | } | ||
1087 | |||
1088 | input_cmd_apply(new_config); | ||
1089 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
1090 | } | ||
1091 | |||
1092 | static struct cmd_results *input_cmd_tap(int argc, char **argv) { | ||
1093 | sway_log(L_DEBUG, "tap for device: %s", current_input_config->identifier); | ||
1094 | struct cmd_results *error = NULL; | ||
1095 | if ((error = checkarg(argc, "tap", EXPECTED_AT_LEAST, 1))) { | ||
1096 | return error; | ||
1097 | } | ||
1098 | if (!current_input_config) { | ||
1099 | return cmd_results_new(CMD_FAILURE, "tap", "No input device defined."); | ||
1100 | } | ||
1101 | struct input_config *new_config = new_input_config(current_input_config->identifier); | ||
1102 | |||
1103 | if (strcasecmp(argv[0], "enabled") == 0) { | ||
1104 | new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; | ||
1105 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
1106 | new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; | ||
1107 | } else { | ||
1108 | return cmd_results_new(CMD_INVALID, "tap", "Expected 'tap <enabled|disabled>'"); | ||
1109 | } | ||
1110 | |||
1111 | sway_log(L_DEBUG, "apply-tap for device: %s", current_input_config->identifier); | ||
1112 | input_cmd_apply(new_config); | ||
1113 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
1114 | } | ||
1115 | |||
1116 | static struct cmd_results *cmd_input(int argc, char **argv) { | ||
1117 | struct cmd_results *error = NULL; | ||
1118 | if ((error = checkarg(argc, "input", EXPECTED_AT_LEAST, 2))) { | ||
1119 | return error; | ||
1120 | } | ||
1121 | |||
1122 | if (config->reading && strcmp("{", argv[1]) == 0) { | ||
1123 | current_input_config = new_input_config(argv[0]); | ||
1124 | sway_log(L_DEBUG, "entering input block: %s", current_input_config->identifier); | ||
1125 | return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); | ||
1126 | } | ||
1127 | |||
1128 | if (argc > 2) { | ||
1129 | int argc_new = argc-2; | ||
1130 | char **argv_new = argv+2; | ||
1131 | |||
1132 | struct cmd_results *res; | ||
1133 | current_input_config = new_input_config(argv[0]); | ||
1134 | if (strcasecmp("click_method", argv[1]) == 0) { | ||
1135 | res = input_cmd_click_method(argc_new, argv_new); | ||
1136 | } else if (strcasecmp("drag_lock", argv[1]) == 0) { | ||
1137 | res = input_cmd_drag_lock(argc_new, argv_new); | ||
1138 | } else if (strcasecmp("dwt", argv[1]) == 0) { | ||
1139 | res = input_cmd_dwt(argc_new, argv_new); | ||
1140 | } else if (strcasecmp("events", argv[1]) == 0) { | ||
1141 | res = input_cmd_events(argc_new, argv_new); | ||
1142 | } else if (strcasecmp("middle_emulation", argv[1]) == 0) { | ||
1143 | res = input_cmd_middle_emulation(argc_new, argv_new); | ||
1144 | } else if (strcasecmp("natural_scroll", argv[1]) == 0) { | ||
1145 | res = input_cmd_natural_scroll(argc_new, argv_new); | ||
1146 | } else if (strcasecmp("pointer_accel", argv[1]) == 0) { | ||
1147 | res = input_cmd_pointer_accel(argc_new, argv_new); | ||
1148 | } else if (strcasecmp("scroll_method", argv[1]) == 0) { | ||
1149 | res = input_cmd_scroll_method(argc_new, argv_new); | ||
1150 | } else if (strcasecmp("tap", argv[1]) == 0) { | ||
1151 | res = input_cmd_tap(argc_new, argv_new); | ||
1152 | } else { | ||
1153 | res = cmd_results_new(CMD_INVALID, "input <device>", "Unknonwn command %s", argv[1]); | ||
1154 | } | ||
1155 | current_input_config = NULL; | ||
1156 | return res; | ||
1157 | } | ||
1158 | |||
1159 | return cmd_results_new(CMD_BLOCK_INPUT, NULL, NULL); | ||
1160 | } | ||
1161 | |||
869 | static struct cmd_results *cmd_output(int argc, char **argv) { | 1162 | static struct cmd_results *cmd_output(int argc, char **argv) { |
870 | struct cmd_results *error = NULL; | 1163 | struct cmd_results *error = NULL; |
871 | if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) { | 1164 | if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) { |
@@ -1683,6 +1976,7 @@ static struct cmd_handler handlers[] = { | |||
1683 | { "for_window", cmd_for_window }, | 1976 | { "for_window", cmd_for_window }, |
1684 | { "fullscreen", cmd_fullscreen }, | 1977 | { "fullscreen", cmd_fullscreen }, |
1685 | { "gaps", cmd_gaps }, | 1978 | { "gaps", cmd_gaps }, |
1979 | { "input", cmd_input }, | ||
1686 | { "kill", cmd_kill }, | 1980 | { "kill", cmd_kill }, |
1687 | { "layout", cmd_layout }, | 1981 | { "layout", cmd_layout }, |
1688 | { "log_colors", cmd_log_colors }, | 1982 | { "log_colors", cmd_log_colors }, |
@@ -2422,6 +2716,18 @@ static struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv | |||
2422 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 2716 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
2423 | } | 2717 | } |
2424 | 2718 | ||
2719 | static struct cmd_handler input_handlers[] = { | ||
2720 | { "click_method", input_cmd_click_method }, | ||
2721 | { "drag_lock", input_cmd_drag_lock }, | ||
2722 | { "dwt", input_cmd_dwt }, | ||
2723 | { "events", input_cmd_events }, | ||
2724 | { "middle_emulation", input_cmd_middle_emulation }, | ||
2725 | { "natural_scroll", input_cmd_natural_scroll }, | ||
2726 | { "pointer_accel", input_cmd_pointer_accel }, | ||
2727 | { "scroll_method", input_cmd_scroll_method }, | ||
2728 | { "tap", input_cmd_tap }, | ||
2729 | }; | ||
2730 | |||
2425 | static struct cmd_handler bar_colors_handlers[] = { | 2731 | static struct cmd_handler bar_colors_handlers[] = { |
2426 | { "active_workspace", bar_colors_cmd_active_workspace }, | 2732 | { "active_workspace", bar_colors_cmd_active_workspace }, |
2427 | { "background", bar_colors_cmd_background }, | 2733 | { "background", bar_colors_cmd_background }, |
@@ -2442,6 +2748,7 @@ static int handler_compare(const void *_a, const void *_b) { | |||
2442 | static struct cmd_handler *find_handler(char *line, enum cmd_status block) { | 2748 | static struct cmd_handler *find_handler(char *line, enum cmd_status block) { |
2443 | struct cmd_handler d = { .command=line }; | 2749 | struct cmd_handler d = { .command=line }; |
2444 | struct cmd_handler *res = NULL; | 2750 | struct cmd_handler *res = NULL; |
2751 | sway_log(L_DEBUG, "find_handler(%s) %d", line, block == CMD_BLOCK_INPUT); | ||
2445 | if (block == CMD_BLOCK_BAR) { | 2752 | if (block == CMD_BLOCK_BAR) { |
2446 | res = bsearch(&d, bar_handlers, | 2753 | res = bsearch(&d, bar_handlers, |
2447 | sizeof(bar_handlers) / sizeof(struct cmd_handler), | 2754 | sizeof(bar_handlers) / sizeof(struct cmd_handler), |
@@ -2450,6 +2757,11 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) { | |||
2450 | res = bsearch(&d, bar_colors_handlers, | 2757 | res = bsearch(&d, bar_colors_handlers, |
2451 | sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), | 2758 | sizeof(bar_colors_handlers) / sizeof(struct cmd_handler), |
2452 | sizeof(struct cmd_handler), handler_compare); | 2759 | sizeof(struct cmd_handler), handler_compare); |
2760 | } else if (block == CMD_BLOCK_INPUT) { | ||
2761 | sway_log(L_DEBUG, "lookng at input handlers"); | ||
2762 | res = bsearch(&d, input_handlers, | ||
2763 | sizeof(input_handlers) / sizeof(struct cmd_handler), | ||
2764 | sizeof(struct cmd_handler), handler_compare); | ||
2453 | } else { | 2765 | } else { |
2454 | res = bsearch(&d, handlers, | 2766 | res = bsearch(&d, handlers, |
2455 | sizeof(handlers) / sizeof(struct cmd_handler), | 2767 | sizeof(handlers) / sizeof(struct cmd_handler), |
diff --git a/sway/config.c b/sway/config.c index ae6a02b1..debd480a 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -6,6 +6,9 @@ | |||
6 | #include <sys/types.h> | 6 | #include <sys/types.h> |
7 | #include <sys/wait.h> | 7 | #include <sys/wait.h> |
8 | #include <signal.h> | 8 | #include <signal.h> |
9 | #include <libinput.h> | ||
10 | #include <limits.h> | ||
11 | #include <float.h> | ||
9 | #include "wayland-desktop-shell-server-protocol.h" | 12 | #include "wayland-desktop-shell-server-protocol.h" |
10 | #include "readline.h" | 13 | #include "readline.h" |
11 | #include "stringop.h" | 14 | #include "stringop.h" |
@@ -16,6 +19,7 @@ | |||
16 | #include "layout.h" | 19 | #include "layout.h" |
17 | #include "input_state.h" | 20 | #include "input_state.h" |
18 | #include "criteria.h" | 21 | #include "criteria.h" |
22 | #include "input.h" | ||
19 | 23 | ||
20 | struct sway_config *config = NULL; | 24 | struct sway_config *config = NULL; |
21 | 25 | ||
@@ -59,6 +63,11 @@ static void free_bar(struct bar_config *bar) { | |||
59 | free(bar); | 63 | free(bar); |
60 | } | 64 | } |
61 | 65 | ||
66 | void free_input_config(struct input_config *ic) { | ||
67 | free(ic->identifier); | ||
68 | free(ic); | ||
69 | } | ||
70 | |||
62 | void free_output_config(struct output_config *oc) { | 71 | void free_output_config(struct output_config *oc) { |
63 | free(oc->name); | 72 | free(oc->name); |
64 | free(oc); | 73 | free(oc); |
@@ -99,6 +108,11 @@ static void free_config(struct sway_config *config) { | |||
99 | } | 108 | } |
100 | list_free(config->criteria); | 109 | list_free(config->criteria); |
101 | 110 | ||
111 | for (i = 0; i < config->input_configs->length; ++i) { | ||
112 | free_input_config(config->input_configs->items[i]); | ||
113 | } | ||
114 | list_free(config->input_configs); | ||
115 | |||
102 | for (i = 0; i < config->output_configs->length; ++i) { | 116 | for (i = 0; i < config->output_configs->length; ++i) { |
103 | free_output_config(config->output_configs->items[i]); | 117 | free_output_config(config->output_configs->items[i]); |
104 | } | 118 | } |
@@ -119,6 +133,7 @@ static void config_defaults(struct sway_config *config) { | |||
119 | config->bars = create_list(); | 133 | config->bars = create_list(); |
120 | config->workspace_outputs = create_list(); | 134 | config->workspace_outputs = create_list(); |
121 | config->criteria = create_list(); | 135 | config->criteria = create_list(); |
136 | config->input_configs = create_list(); | ||
122 | config->output_configs = create_list(); | 137 | config->output_configs = create_list(); |
123 | 138 | ||
124 | config->cmd_queue = create_list(); | 139 | config->cmd_queue = create_list(); |
@@ -294,6 +309,14 @@ bool read_config(FILE *file, bool is_active) { | |||
294 | } | 309 | } |
295 | break; | 310 | break; |
296 | 311 | ||
312 | case CMD_BLOCK_INPUT: | ||
313 | if (block == CMD_BLOCK_END) { | ||
314 | block = CMD_BLOCK_INPUT; | ||
315 | } else { | ||
316 | sway_log(L_ERROR, "Invalid block '%s'", line); | ||
317 | } | ||
318 | break; | ||
319 | |||
297 | case CMD_BLOCK_BAR: | 320 | case CMD_BLOCK_BAR: |
298 | if (block == CMD_BLOCK_END) { | 321 | if (block == CMD_BLOCK_END) { |
299 | block = CMD_BLOCK_BAR; | 322 | block = CMD_BLOCK_BAR; |
@@ -318,6 +341,12 @@ bool read_config(FILE *file, bool is_active) { | |||
318 | block = CMD_BLOCK_END; | 341 | block = CMD_BLOCK_END; |
319 | break; | 342 | break; |
320 | 343 | ||
344 | case CMD_BLOCK_INPUT: | ||
345 | sway_log(L_DEBUG, "End of input block"); | ||
346 | current_input_config = NULL; | ||
347 | block = CMD_BLOCK_END; | ||
348 | break; | ||
349 | |||
321 | case CMD_BLOCK_BAR: | 350 | case CMD_BLOCK_BAR: |
322 | sway_log(L_DEBUG, "End of bar block"); | 351 | sway_log(L_DEBUG, "End of bar block"); |
323 | config->current_bar = NULL; | 352 | config->current_bar = NULL; |
@@ -353,6 +382,12 @@ bool read_config(FILE *file, bool is_active) { | |||
353 | return success; | 382 | return success; |
354 | } | 383 | } |
355 | 384 | ||
385 | int input_identifier_cmp(const void *item, const void *data) { | ||
386 | const struct input_config *ic = item; | ||
387 | const char *identifier = data; | ||
388 | return strcmp(ic->identifier, identifier); | ||
389 | } | ||
390 | |||
356 | int output_name_cmp(const void *item, const void *data) { | 391 | int output_name_cmp(const void *item, const void *data) { |
357 | const struct output_config *output = item; | 392 | const struct output_config *output = item; |
358 | const char *name = data; | 393 | const char *name = data; |
@@ -360,6 +395,42 @@ int output_name_cmp(const void *item, const void *data) { | |||
360 | return strcmp(output->name, name); | 395 | return strcmp(output->name, name); |
361 | } | 396 | } |
362 | 397 | ||
398 | void merge_input_config(struct input_config *dst, struct input_config *src) { | ||
399 | if (src->identifier) { | ||
400 | if (dst->identifier) { | ||
401 | free(dst->identifier); | ||
402 | } | ||
403 | dst->identifier = strdup(src->identifier); | ||
404 | } | ||
405 | if (src->click_method != INT_MIN) { | ||
406 | dst->click_method = src->click_method; | ||
407 | } | ||
408 | if (src->drag_lock != INT_MIN) { | ||
409 | dst->drag_lock = src->drag_lock; | ||
410 | } | ||
411 | if (src->dwt != INT_MIN) { | ||
412 | dst->dwt = src->dwt; | ||
413 | } | ||
414 | if (src->middle_emulation != INT_MIN) { | ||
415 | dst->middle_emulation = src->middle_emulation; | ||
416 | } | ||
417 | if (src->natural_scroll != INT_MIN) { | ||
418 | dst->natural_scroll = src->natural_scroll; | ||
419 | } | ||
420 | if (src->pointer_accel != FLT_MIN) { | ||
421 | dst->pointer_accel = src->pointer_accel; | ||
422 | } | ||
423 | if (src->scroll_method != INT_MIN) { | ||
424 | dst->scroll_method = src->scroll_method; | ||
425 | } | ||
426 | if (src->send_events != INT_MIN) { | ||
427 | dst->send_events = src->send_events; | ||
428 | } | ||
429 | if (src->tap != INT_MIN) { | ||
430 | dst->tap = src->tap; | ||
431 | } | ||
432 | } | ||
433 | |||
363 | void merge_output_config(struct output_config *dst, struct output_config *src) { | 434 | void merge_output_config(struct output_config *dst, struct output_config *src) { |
364 | if (src->name) { | 435 | if (src->name) { |
365 | if (dst->name) { | 436 | if (dst->name) { |
@@ -508,6 +579,51 @@ void load_swaybars(swayc_t *output, int output_idx) { | |||
508 | list_free(bars); | 579 | list_free(bars); |
509 | } | 580 | } |
510 | 581 | ||
582 | void apply_input_config(struct input_config *ic, struct libinput_device *dev) { | ||
583 | if (ic) { | ||
584 | sway_log(L_DEBUG, | ||
585 | "apply_input_config(%s)", | ||
586 | ic->identifier); | ||
587 | } | ||
588 | |||
589 | if (ic && ic->click_method != INT_MIN) { | ||
590 | sway_log(L_DEBUG, "apply_input_config(%s) click_set_method(%d)", ic->identifier, ic->click_method); | ||
591 | libinput_device_config_click_set_method(dev, ic->click_method); | ||
592 | } | ||
593 | if (ic && ic->drag_lock != INT_MIN) { | ||
594 | sway_log(L_DEBUG, "apply_input_config(%s) tap_set_drag_lock_enabled(%d)", ic->identifier, ic->click_method); | ||
595 | libinput_device_config_tap_set_drag_lock_enabled(dev, ic->drag_lock); | ||
596 | } | ||
597 | if (ic && ic->dwt != INT_MIN) { | ||
598 | sway_log(L_DEBUG, "apply_input_config(%s) dwt_set_enabled(%d)", ic->identifier, ic->dwt); | ||
599 | libinput_device_config_dwt_set_enabled(dev, ic->dwt); | ||
600 | } | ||
601 | if (ic && ic->middle_emulation != INT_MIN) { | ||
602 | sway_log(L_DEBUG, "apply_input_config(%s) middle_emulation_set_enabled(%d)", ic->identifier, ic->middle_emulation); | ||
603 | libinput_device_config_middle_emulation_set_enabled(dev, ic->middle_emulation); | ||
604 | } | ||
605 | if (ic && ic->natural_scroll != INT_MIN) { | ||
606 | sway_log(L_DEBUG, "apply_input_config(%s) natural_scroll_set_enabled(%d)", ic->identifier, ic->natural_scroll); | ||
607 | libinput_device_config_scroll_set_natural_scroll_enabled(dev, ic->natural_scroll); | ||
608 | } | ||
609 | if (ic && ic->pointer_accel != FLT_MIN) { | ||
610 | sway_log(L_DEBUG, "apply_input_config(%s) accel_set_speed(%f)", ic->identifier, ic->pointer_accel); | ||
611 | libinput_device_config_accel_set_speed(dev, ic->pointer_accel); | ||
612 | } | ||
613 | if (ic && ic->scroll_method != INT_MIN) { | ||
614 | sway_log(L_DEBUG, "apply_input_config(%s) scroll_set_method(%d)", ic->identifier, ic->scroll_method); | ||
615 | libinput_device_config_scroll_set_method(dev, ic->scroll_method); | ||
616 | } | ||
617 | if (ic && ic->send_events != INT_MIN) { | ||
618 | sway_log(L_DEBUG, "apply_input_config(%s) send_events_set_mode(%d)", ic->identifier, ic->send_events); | ||
619 | libinput_device_config_send_events_set_mode(dev, ic->send_events); | ||
620 | } | ||
621 | if (ic && ic->tap != INT_MIN) { | ||
622 | sway_log(L_DEBUG, "apply_input_config(%s) tap_set_enabled(%d)", ic->identifier, ic->tap); | ||
623 | libinput_device_config_tap_set_enabled(dev, ic->tap); | ||
624 | } | ||
625 | } | ||
626 | |||
511 | void apply_output_config(struct output_config *oc, swayc_t *output) { | 627 | void apply_output_config(struct output_config *oc, swayc_t *output) { |
512 | if (oc && oc->width > 0 && oc->height > 0) { | 628 | if (oc && oc->width > 0 && oc->height > 0) { |
513 | output->width = oc->width; | 629 | output->width = oc->width; |
diff --git a/sway/handlers.c b/sway/handlers.c index 60bfac87..b1c0e26a 100644 --- a/sway/handlers.c +++ b/sway/handlers.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <xkbcommon/xkbcommon.h> | 1 | #include <xkbcommon/xkbcommon.h> |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <stdbool.h> | 3 | #include <stdbool.h> |
4 | #include <libinput.h> | ||
4 | #include <math.h> | 5 | #include <math.h> |
5 | #include <wlc/wlc.h> | 6 | #include <wlc/wlc.h> |
6 | #include <wlc/wlc-wayland.h> | 7 | #include <wlc/wlc-wayland.h> |
@@ -21,6 +22,8 @@ | |||
21 | #include "extensions.h" | 22 | #include "extensions.h" |
22 | #include "criteria.h" | 23 | #include "criteria.h" |
23 | #include "ipc-server.h" | 24 | #include "ipc-server.h" |
25 | #include "list.h" | ||
26 | #include "input.h" | ||
24 | 27 | ||
25 | // Event should be sent to client | 28 | // Event should be sent to client |
26 | #define EVENT_PASSTHROUGH false | 29 | #define EVENT_PASSTHROUGH false |
@@ -30,6 +33,37 @@ | |||
30 | 33 | ||
31 | /* Handles */ | 34 | /* Handles */ |
32 | 35 | ||
36 | static bool handle_input_created(struct libinput_device *device) { | ||
37 | const char *identifier = libinput_dev_unique_id(device); | ||
38 | sway_log(L_INFO, "Found input device (%s)", identifier); | ||
39 | |||
40 | list_add(input_devices, device); | ||
41 | |||
42 | struct input_config *ic = NULL; | ||
43 | int i; | ||
44 | for (i = 0; i < config->input_configs->length; ++i) { | ||
45 | struct input_config *cur = config->input_configs->items[i]; | ||
46 | if (strcasecmp(identifier, cur->identifier) == 0) { | ||
47 | ic = cur; | ||
48 | break; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | apply_input_config(ic, device); | ||
53 | return true; | ||
54 | } | ||
55 | |||
56 | static void handle_input_destroyed(struct libinput_device *device) { | ||
57 | int i; | ||
58 | list_t *list = input_devices; | ||
59 | for (i = 0; i < list->length; ++i) { | ||
60 | if(((struct libinput_device *)list->items[i]) == device) { | ||
61 | list_del(list, i); | ||
62 | break; | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
33 | static bool handle_output_created(wlc_handle output) { | 67 | static bool handle_output_created(wlc_handle output) { |
34 | swayc_t *op = new_output(output); | 68 | swayc_t *op = new_output(output); |
35 | 69 | ||
@@ -660,5 +694,9 @@ struct wlc_interface interface = { | |||
660 | }, | 694 | }, |
661 | .compositor = { | 695 | .compositor = { |
662 | .ready = handle_wlc_ready | 696 | .ready = handle_wlc_ready |
697 | }, | ||
698 | .input = { | ||
699 | .created = handle_input_created, | ||
700 | .destroyed = handle_input_destroyed | ||
663 | } | 701 | } |
664 | }; | 702 | }; |
diff --git a/sway/input.c b/sway/input.c new file mode 100644 index 00000000..fe0d1aff --- /dev/null +++ b/sway/input.c | |||
@@ -0,0 +1,54 @@ | |||
1 | #include <ctype.h> | ||
2 | #include <float.h> | ||
3 | #include <limits.h> | ||
4 | #include <stdio.h> | ||
5 | #include <string.h> | ||
6 | #include <libinput.h> | ||
7 | #include "config.h" | ||
8 | #include "input.h" | ||
9 | #include "list.h" | ||
10 | #include "log.h" | ||
11 | |||
12 | struct input_config *new_input_config(const char* identifier) { | ||
13 | struct input_config *input = calloc(1, sizeof(struct input_config)); | ||
14 | sway_log(L_DEBUG, "new_input_config(%s)", identifier); | ||
15 | input->identifier = strdup(identifier); | ||
16 | |||
17 | input->tap = INT_MIN; | ||
18 | input->drag_lock = INT_MIN; | ||
19 | input->dwt = INT_MIN; | ||
20 | input->send_events = INT_MIN; | ||
21 | input->click_method = INT_MIN; | ||
22 | input->middle_emulation = INT_MIN; | ||
23 | input->natural_scroll = INT_MIN; | ||
24 | input->pointer_accel = FLT_MIN; | ||
25 | input->scroll_method = INT_MIN; | ||
26 | |||
27 | return input; | ||
28 | } | ||
29 | |||
30 | char *libinput_dev_unique_id(struct libinput_device *device) { | ||
31 | int vendor = libinput_device_get_id_vendor(device); | ||
32 | int product = libinput_device_get_id_product(device); | ||
33 | char *name = strdup(libinput_device_get_name(device)); | ||
34 | |||
35 | char *p = name; | ||
36 | for (; *p; ++p) { | ||
37 | if (*p == ' ') { | ||
38 | *p = '_'; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | sway_log(L_DEBUG, "rewritten name %s", name); | ||
43 | |||
44 | int len = strlen(name) + sizeof(char) * 6; | ||
45 | char *identifier = malloc(len); | ||
46 | |||
47 | const char *fmt = "%d:%d:%s"; | ||
48 | snprintf(identifier, len, fmt, vendor, product, name); | ||
49 | free(name); | ||
50 | return identifier; | ||
51 | } | ||
52 | |||
53 | list_t *input_devices = NULL; | ||
54 | struct input_config *current_input_config = NULL; | ||
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 8d92b919..58a291cd 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <ctype.h> | 13 | #include <ctype.h> |
14 | #include <json-c/json.h> | 14 | #include <json-c/json.h> |
15 | #include <list.h> | 15 | #include <list.h> |
16 | #include <libinput.h> | ||
16 | #include "ipc-server.h" | 17 | #include "ipc-server.h" |
17 | #include "log.h" | 18 | #include "log.h" |
18 | #include "config.h" | 19 | #include "config.h" |
@@ -20,6 +21,7 @@ | |||
20 | #include "list.h" | 21 | #include "list.h" |
21 | #include "stringop.h" | 22 | #include "stringop.h" |
22 | #include "util.h" | 23 | #include "util.h" |
24 | #include "input.h" | ||
23 | 25 | ||
24 | static int ipc_socket = -1; | 26 | static int ipc_socket = -1; |
25 | static struct wlc_event_source *ipc_event_source = NULL; | 27 | static struct wlc_event_source *ipc_event_source = NULL; |
@@ -325,6 +327,24 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
325 | json_object_put(workspaces); // free | 327 | json_object_put(workspaces); // free |
326 | break; | 328 | break; |
327 | } | 329 | } |
330 | case IPC_GET_INPUTS: | ||
331 | { | ||
332 | json_object *inputs = json_object_new_array(); | ||
333 | if (input_devices) { | ||
334 | for(int i=0; i<input_devices->length; i++) { | ||
335 | struct libinput_device *device = input_devices->items[i]; | ||
336 | char* identifier = libinput_dev_unique_id(device); | ||
337 | json_object *device_object = json_object_new_object(); | ||
338 | json_object_object_add(device_object, "identifier", json_object_new_string(identifier)); | ||
339 | json_object_array_add(inputs, device_object); | ||
340 | free(identifier); | ||
341 | } | ||
342 | } | ||
343 | const char *json_string = json_object_to_json_string(inputs); | ||
344 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | ||
345 | json_object_put(inputs); | ||
346 | break; | ||
347 | } | ||
328 | case IPC_GET_OUTPUTS: | 348 | case IPC_GET_OUTPUTS: |
329 | { | 349 | { |
330 | json_object *outputs = json_object_new_array(); | 350 | json_object *outputs = json_object_new_array(); |
diff --git a/sway/main.c b/sway/main.c index e85f7269..bec6a725 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "handlers.h" | 17 | #include "handlers.h" |
18 | #include "ipc-client.h" | 18 | #include "ipc-client.h" |
19 | #include "ipc-server.h" | 19 | #include "ipc-server.h" |
20 | #include "input.h" | ||
20 | #include "sway.h" | 21 | #include "sway.h" |
21 | 22 | ||
22 | static bool terminate_request = false; | 23 | static bool terminate_request = false; |
@@ -173,6 +174,8 @@ int main(int argc, char **argv) { | |||
173 | wlc_log_set_handler(wlc_log_handler); | 174 | wlc_log_set_handler(wlc_log_handler); |
174 | detect_proprietary(); | 175 | detect_proprietary(); |
175 | 176 | ||
177 | input_devices = create_list(); | ||
178 | |||
176 | /* Changing code earlier than this point requires detailed review */ | 179 | /* Changing code earlier than this point requires detailed review */ |
177 | /* (That code runs as root on systems without logind, and wlc_init drops to | 180 | /* (That code runs as root on systems without logind, and wlc_init drops to |
178 | * another user.) */ | 181 | * another user.) */ |
@@ -208,6 +211,10 @@ int main(int argc, char **argv) { | |||
208 | wlc_run(); | 211 | wlc_run(); |
209 | } | 212 | } |
210 | 213 | ||
214 | if (input_devices) { | ||
215 | free(input_devices); | ||
216 | } | ||
217 | |||
211 | ipc_terminate(); | 218 | ipc_terminate(); |
212 | 219 | ||
213 | return 0; | 220 | return 0; |
diff --git a/sway/sway-input.5.txt b/sway/sway-input.5.txt new file mode 100644 index 00000000..ec5d1314 --- /dev/null +++ b/sway/sway-input.5.txt | |||
@@ -0,0 +1,46 @@ | |||
1 | ///// | ||
2 | vim:set ts=4 sw=4 tw=82 noet: | ||
3 | ///// | ||
4 | sway (5) | ||
5 | ======== | ||
6 | |||
7 | Name | ||
8 | ---- | ||
9 | sway - input configuration file and commands | ||
10 | |||
11 | Description | ||
12 | ----------- | ||
13 | |||
14 | Sway allows for configuration of libinput dveices. | ||
15 | |||
16 | |||
17 | Commands | ||
18 | -------- | ||
19 | |||
20 | **input** <identifier> click_method <none|button_areas|clickfinger>: | ||
21 | Changes the click method for the specified device. | ||
22 | |||
23 | **input** <identifier> drag_lock <enabled|disabled>: | ||
24 | Enables or disables drag lock for specified input device. | ||
25 | |||
26 | **input** <identifier> dwt <enabled|disabled>: | ||
27 | Enables or disables disable-while-typing for the specified input device. | ||
28 | |||
29 | **input** <identifier> events <enable|disabled>: | ||
30 | Enables or disables send_events for specified input device. | ||
31 | (Disabling send_events disables the input device) | ||
32 | |||
33 | **input** <identifier> middle_emulation <enabled|disabled>: | ||
34 | Enables or disables middle click emulation. | ||
35 | |||
36 | **input** <identifier> natural_scroll <enabled|disabled>: | ||
37 | Enables or disables natural scrolling for the specified input device. | ||
38 | |||
39 | **input** <identifier> pointer_accel <[-1,1]>: | ||
40 | Changes the pointer acceleration for the specified input device. | ||
41 | |||
42 | **input** <identifier> scroll_method <none|two_finger|edge|on_button_down>: | ||
43 | Changes the scroll method for the specified input device. | ||
44 | |||
45 | **input** <identifier> tap <enabled|disabled>: | ||
46 | Enables or disables tap for specified input device. | ||
diff --git a/swaymsg/main.c b/swaymsg/main.c index dac84a9b..22572b6f 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c | |||
@@ -87,6 +87,8 @@ int main(int argc, char **argv) { | |||
87 | type = IPC_COMMAND; | 87 | type = IPC_COMMAND; |
88 | } else if (strcasecmp(cmdtype, "get_workspaces") == 0) { | 88 | } else if (strcasecmp(cmdtype, "get_workspaces") == 0) { |
89 | type = IPC_GET_WORKSPACES; | 89 | type = IPC_GET_WORKSPACES; |
90 | } else if (strcasecmp(cmdtype, "get_inputs") == 0) { | ||
91 | type = IPC_GET_INPUTS; | ||
90 | } else if (strcasecmp(cmdtype, "get_outputs") == 0) { | 92 | } else if (strcasecmp(cmdtype, "get_outputs") == 0) { |
91 | type = IPC_GET_OUTPUTS; | 93 | type = IPC_GET_OUTPUTS; |
92 | } else if (strcasecmp(cmdtype, "get_tree") == 0) { | 94 | } else if (strcasecmp(cmdtype, "get_tree") == 0) { |
diff --git a/swaymsg/swaymsg.1.txt b/swaymsg/swaymsg.1.txt index 984780fa..c3af28d5 100644 --- a/swaymsg/swaymsg.1.txt +++ b/swaymsg/swaymsg.1.txt | |||
@@ -43,6 +43,9 @@ IPC Message Types | |||
43 | *get_workspaces*:: | 43 | *get_workspaces*:: |
44 | Gets a JSON-encoded list of workspaces and their status. | 44 | Gets a JSON-encoded list of workspaces and their status. |
45 | 45 | ||
46 | *get_inputs*:: | ||
47 | Gets a JSON-encoded list of current inputs. | ||
48 | |||
46 | *get_outputs*:: | 49 | *get_outputs*:: |
47 | Gets a JSON-encoded list of current outputs. | 50 | Gets a JSON-encoded list of current outputs. |
48 | 51 | ||