diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c936550 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Sankalp Tharu + +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: + +The above copyright notice and this permission notice 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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7fc21f4 --- /dev/null +++ b/Makefile @@ -0,0 +1,82 @@ +CC = gcc +CFLAGS = -Wall -Wextra -std=c99 +PREFIX ?= /usr + +# Pass PACKAGE_PREFIX macro for config.h +CPPFLAGS = -DPACKAGE_PREFIX=\"$(PREFIX)\" $(shell pkg-config --cflags libevdev json-c libpulse-simple sndfile) + +LDFLAGS_SOUND = -ljson-c -lpulse -lpulse-simple -lsndfile -lpthread +LDFLAGS_KEYBOARD = $(shell pkg-config --libs libevdev libinput libudev) -lpthread + +# Targets +KeyVibe_TARGET = keyvibe +SOUND_TARGET = keyboard_sound_player +KEYBOARD_TARGET = get_key_presses + +# Sources +KeyVibe_SOURCE = keyvibe.c +SOUND_SOURCE = keyboard_sound_player.c +KEYBOARD_SOURCE = get_key_presses.c + +# Install paths +BINDIR = $(PREFIX)/bin +SHAREDIR = $(PREFIX)/share/keyvibe +UDEV_RULE = /etc/udev/rules.d/99-keyvibe-allow-keyboard.rules + +all: $(KeyVibe_TARGET) $(SOUND_TARGET) $(KEYBOARD_TARGET) + + +# Build main launcher (needs json-c) +$(KeyVibe_TARGET): $(KeyVibe_SOURCE) + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< -ljson-c + +$(SOUND_TARGET): $(SOUND_SOURCE) + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(LDFLAGS_SOUND) + +$(KEYBOARD_TARGET): $(KEYBOARD_SOURCE) + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(LDFLAGS_KEYBOARD) + +clean: + rm -f $(KeyVibe_TARGET) $(SOUND_TARGET) $(KEYBOARD_TARGET) + +test: all + @echo "Testing sound packs:" + ./$(KeyVibe_TARGET) --list + @echo "" + @echo "To run KeyVibe:" + @echo " sudo ./$(KeyVibe_TARGET) # Default sound" + @echo " sudo ./$(KeyVibe_TARGET) -s cherrymx-blue-abs # Specific sound" + @echo " sudo ./$(KeyVibe_TARGET) --help # Show help" + +install: + @echo "Installing KeyVibe to $(DESTDIR)$(BINDIR) and $(DESTDIR)$(SHAREDIR)..." + install -Dm755 $(KeyVibe_TARGET) $(DESTDIR)$(BINDIR)/$(KeyVibe_TARGET) + install -Dm755 $(SOUND_TARGET) $(DESTDIR)$(BINDIR)/$(SOUND_TARGET) + install -Dm755 $(KEYBOARD_TARGET) $(DESTDIR)$(BINDIR)/$(KEYBOARD_TARGET) + install -d $(DESTDIR)$(SHAREDIR) + cp -r audio $(DESTDIR)$(SHAREDIR)/ + @echo "Installing udev rule for non-root keyboard access..." + @echo '# Allow non-root access to input event devices for active seat users and input group' | sudo tee $(UDEV_RULE) >/dev/null + @echo 'SUBSYSTEM=="input", KERNEL=="event*", TAG+="uaccess", GROUP="input", MODE="0660"' | sudo tee -a $(UDEV_RULE) >/dev/null + @echo "Reloading udev rules..." + @sudo udevadm control --reload-rules && sudo udevadm trigger --subsystem-match=input --action=change || true + @echo "Applying immediate ACLs to current user for existing input devices..." + @CURRENT_USER=$${SUDO_USER:-$$USER}; \ + for dev in /dev/input/event*; do \ + [ -e "$$dev" ] && sudo setfacl -m u:$${CURRENT_USER}:rw "$$dev" || true; \ + done + @echo "Note: ACLs applied for the current session. Future devices are handled by udev via TAG+=uaccess." + @echo "Installation complete." + +uninstall: + @echo "Uninstalling KeyVibe from $(DESTDIR)$(BINDIR) and $(DESTDIR)$(SHAREDIR)..." + rm -f $(DESTDIR)$(BINDIR)/$(KeyVibe_TARGET) + rm -f $(DESTDIR)$(BINDIR)/$(SOUND_TARGET) + rm -f $(DESTDIR)$(BINDIR)/$(KEYBOARD_TARGET) + rm -rf $(DESTDIR)$(SHAREDIR) + @echo "Removing udev rule..." + @sudo rm -f $(UDEV_RULE) || true + @sudo udevadm control --reload-rules && sudo udevadm trigger --subsystem-match=input --action=change || true + @echo "Uninstallation complete." + +.PHONY: all clean test install uninstall diff --git a/audio/cherrymx-black-abs/config.json b/audio/cherrymx-black-abs/config.json new file mode 100644 index 0000000..fdf0e34 --- /dev/null +++ b/audio/cherrymx-black-abs/config.json @@ -0,0 +1,657 @@ +{ + "id": "custom-sound-pack-1582654366773", + "name": "CherryMX Black - ABS keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 2926, + 125 + ], + "1-up": [ + 3051, + 77 + ], + "2": [ + 12965, + 112 + ], + "2-up": [ + 13078, + 91 + ], + "3": [ + 13470, + 128 + ], + "3-up": [ + 13598, + 77 + ], + "4": [ + 13993, + 101 + ], + "4-up": [ + 14094, + 89 + ], + "5": [ + 14481, + 105 + ], + "5-up": [ + 14618, + 122 + ], + "6": [ + 14994, + 137 + ], + "6-up": [ + 15131, + 77 + ], + "7": [ + 15505, + 128 + ], + "7-up": [ + 15633, + 90 + ], + "8": [ + 15990, + 132 + ], + "8-up": [ + 16122, + 77 + ], + "9": [ + 16529, + 115 + ], + "9-up": [ + 16644, + 77 + ], + "10": [ + 17012, + 138 + ], + "10-up": [ + 17150, + 77 + ], + "11": [ + 17550, + 131 + ], + "11-up": [ + 17681, + 77 + ], + "12": [ + 18059, + 120 + ], + "12-up": [ + 18179, + 77 + ], + "13": [ + 18584, + 92 + ], + "13-up": [ + 18675, + 77 + ], + "14": [ + 19065, + 123 + ], + "14-up": [ + 19188, + 108 + ], + "15": [ + 21734, + 137 + ], + "15-up": [ + 21871, + 87 + ], + "16": [ + 22245, + 136 + ], + "16-up": [ + 22380, + 77 + ], + "17": [ + 22790, + 123 + ], + "17-up": [ + 22913, + 77 + ], + "18": [ + 23317, + 112 + ], + "18-up": [ + 23429, + 65 + ], + "19": [ + 23817, + 124 + ], + "19-up": [ + 23941, + 77 + ], + "20": [ + 24297, + 131 + ], + "20-up": [ + 24428, + 77 + ], + "21": [ + 24816, + 109 + ], + "21-up": [ + 24925, + 77 + ], + "22": [ + 25313, + 119 + ], + "22-up": [ + 25431, + 77 + ], + "23": [ + 25795, + 118 + ], + "23-up": [ + 25913, + 77 + ], + "24": [ + 26309, + 112 + ], + "24-up": [ + 26421, + 64 + ], + "25": [ + 26804, + 117 + ], + "25-up": [ + 26921, + 77 + ], + "26": [ + 27330, + 98 + ], + "26-up": [ + 27428, + 77 + ], + "27": [ + 27901, + 95 + ], + "27-up": [ + 28017, + 77 + ], + "28": [ + 36902, + 101 + ], + "28-up": [ + 37003, + 135 + ], + "29": [ + 45327, + 83 + ], + "29-up": [ + 45410, + 77 + ], + "30": [ + 31542, + 99 + ], + "30-up": [ + 31657, + 77 + ], + "31": [ + 32031, + 115 + ], + "31-up": [ + 32146, + 77 + ], + "32": [ + 32492, + 100 + ], + "32-up": [ + 32592, + 78 + ], + "33": [ + 32973, + 112 + ], + "33-up": [ + 33108, + 77 + ], + "34": [ + 33453, + 103 + ], + "34-up": [ + 33568, + 77 + ], + "35": [ + 33982, + 122 + ], + "35-up": [ + 34114, + 77 + ], + "36": [ + 34425, + 86 + ], + "36-up": [ + 34541, + 77 + ], + "37": [ + 34932, + 111 + ], + "37-up": [ + 35043, + 77 + ], + "38": [ + 35410, + 135 + ], + "38-up": [ + 35545, + 77 + ], + "39": [ + 35914, + 132 + ], + "39-up": [ + 36046, + 77 + ], + "40": [ + 36428, + 129 + ], + "40-up": [ + 36557, + 77 + ], + "41": [ + 12476, + 120 + ], + "41-up": [ + 12596, + 92 + ], + "42": [ + 38136, + 142 + ], + "42-up": [ + 38278, + 116 + ], + "43": [ + 28429, + 108 + ], + "43-up": [ + 28537, + 95 + ], + "44": [ + 38694, + 102 + ], + "44-up": [ + 38796, + 80 + ], + "45": [ + 39148, + 121 + ], + "45-up": [ + 39269, + 91 + ], + "46": [ + 39632, + 120 + ], + "46-up": [ + 39752, + 82 + ], + "47": [ + 40136, + 134 + ], + "47-up": [ + 40270, + 83 + ], + "48": [ + 40621, + 122 + ], + "48-up": [ + 40743, + 105 + ], + "49": [ + 41103, + 131 + ], + "50": [ + 41610, + 186 + ], + "51": [ + 42110, + 183 + ], + "52": [ + 42594, + 180 + ], + "53": [ + 43105, + 190 + ], + "54": [ + 43565, + 273 + ], + "55": [ + 11270, + 200 + ], + "56": [ + 45750, + 164 + ], + "57": [ + 51541, + 287 + ], + "58": [ + 31011, + 251 + ], + "59": [ + 3610, + 195 + ], + "60": [ + 4210, + 180 + ], + "61": [ + 4758, + 180 + ], + "62": [ + 5250, + 199 + ], + "63": [ + 5831, + 209 + ], + "64": [ + 6396, + 210 + ], + "65": [ + 6900, + 210 + ], + "66": [ + 7443, + 221 + ], + "67": [ + 7955, + 181 + ], + "68": [ + 8504, + 209 + ], + "69": [ + 10132, + 208 + ], + "70": [ + 10763, + 160 + ], + "71": [ + 19634, + 171 + ], + "72": [ + 20143, + 202 + ], + "73": [ + 20647, + 193 + ], + "74": [ + 18052, + 186 + ], + "75": [ + 28914, + 212 + ], + "76": [ + 29427, + 177 + ], + "77": [ + 29928, + 190 + ], + "78": [ + 19065, + 220 + ], + "79": [ + 49837, + 176 + ], + "80": [ + 50333, + 179 + ], + "81": [ + 50783, + 221 + ], + "82": [ + 43565, + 273 + ], + "83": [ + 44251, + 220 + ], + "87": [ + 9046, + 187 + ], + "88": [ + 9582, + 191 + ], + "3612": [ + 36902, + 234 + ], + "3613": [ + 49329, + 164 + ], + "3637": [ + 10763, + 160 + ], + "3639": [ + 10132, + 208 + ], + "3640": [ + 48381, + 168 + ], + "3653": [ + 11270, + 200 + ], + "3655": [ + 20143, + 202 + ], + "3657": [ + 20647, + 193 + ], + "3663": [ + 29427, + 177 + ], + "3665": [ + 29928, + 190 + ], + "3666": [ + 19634, + 171 + ], + "3667": [ + 28914, + 212 + ], + "3675": [ + 46199, + 199 + ], + "3676": [ + 47929, + 149 + ], + "3677": [ + 49329, + 164 + ], + "57416": [ + 44251, + 220 + ], + "57419": [ + 49837, + 176 + ], + "57421": [ + 50783, + 221 + ], + "57424": [ + 50333, + 179 + ], + "60999": [ + 20143, + 202 + ], + "61000": [ + 44251, + 220 + ], + "61001": [ + 20647, + 193 + ], + "61003": [ + 49837, + 176 + ], + "61005": [ + 50783, + 221 + ], + "61007": [ + 29427, + 177 + ], + "61008": [ + 50333, + 179 + ], + "61009": [ + 29928, + 190 + ], + "61010": [ + 19634, + 171 + ], + "61011": [ + 28914, + 212 + ] + } +} diff --git a/audio/cherrymx-black-abs/sound.ogg b/audio/cherrymx-black-abs/sound.ogg new file mode 100644 index 0000000..2318e11 Binary files /dev/null and b/audio/cherrymx-black-abs/sound.ogg differ diff --git a/audio/cherrymx-black-pbt/config.json b/audio/cherrymx-black-pbt/config.json new file mode 100644 index 0000000..85a847b --- /dev/null +++ b/audio/cherrymx-black-pbt/config.json @@ -0,0 +1,465 @@ +{ + "id": "custom-sound-pack-1582654366773", + "name": "CherryMX Black - PBT keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 2078, + 176 + ], + "2": [ + 9291, + 164 + ], + "3": [ + 9702, + 153 + ], + "4": [ + 10097, + 140 + ], + "5": [ + 10459, + 165 + ], + "6": [ + 10859, + 165 + ], + "7": [ + 11250, + 165 + ], + "8": [ + 11648, + 159 + ], + "9": [ + 12014, + 150 + ], + "10": [ + 12414, + 136 + ], + "11": [ + 12826, + 137 + ], + "12": [ + 13227, + 138 + ], + "13": [ + 13625, + 134 + ], + "14": [ + 14035, + 137 + ], + "15": [ + 15707, + 163 + ], + "16": [ + 16114, + 157 + ], + "17": [ + 16515, + 150 + ], + "18": [ + 16889, + 147 + ], + "19": [ + 17253, + 161 + ], + "20": [ + 17630, + 156 + ], + "21": [ + 18024, + 140 + ], + "22": [ + 18416, + 134 + ], + "23": [ + 18815, + 140 + ], + "24": [ + 19229, + 128 + ], + "25": [ + 19632, + 127 + ], + "26": [ + 20024, + 131 + ], + "27": [ + 20438, + 131 + ], + "28": [ + 27154, + 171 + ], + "29": [ + 33678, + 163 + ], + "30": [ + 22850, + 160 + ], + "31": [ + 23243, + 156 + ], + "32": [ + 23645, + 155 + ], + "33": [ + 24034, + 152 + ], + "34": [ + 24445, + 146 + ], + "35": [ + 24824, + 148 + ], + "36": [ + 25181, + 164 + ], + "37": [ + 25593, + 145 + ], + "38": [ + 25993, + 139 + ], + "39": [ + 26393, + 136 + ], + "40": [ + 26801, + 128 + ], + "41": [ + 8869, + 181 + ], + "42": [ + 28061, + 186 + ], + "43": [ + 20858, + 129 + ], + "44": [ + 28466, + 161 + ], + "45": [ + 28845, + 151 + ], + "46": [ + 29208, + 156 + ], + "47": [ + 29571, + 144 + ], + "48": [ + 29926, + 159 + ], + "49": [ + 30248, + 139 + ], + "50": [ + 30598, + 140 + ], + "51": [ + 30981, + 130 + ], + "52": [ + 31353, + 128 + ], + "53": [ + 31740, + 126 + ], + "54": [ + 32135, + 169 + ], + "55": [ + 8372, + 140 + ], + "56": [ + 34451, + 164 + ], + "57": [ + 34906, + 168 + ], + "58": [ + 22462, + 166 + ], + "59": [ + 2511, + 186 + ], + "60": [ + 2919, + 177 + ], + "61": [ + 3307, + 185 + ], + "62": [ + 3700, + 176 + ], + "63": [ + 4164, + 148 + ], + "64": [ + 4613, + 155 + ], + "65": [ + 5024, + 150 + ], + "66": [ + 5438, + 147 + ], + "67": [ + 5862, + 149 + ], + "68": [ + 6270, + 138 + ], + "69": [ + 7547, + 134 + ], + "70": [ + 7957, + 141 + ], + "71": [ + 14524, + 141 + ], + "72": [ + 14949, + 119 + ], + "73": [ + 15311, + 143 + ], + "74": [ + 13227, + 138 + ], + "75": [ + 21286, + 113 + ], + "76": [ + 21671, + 146 + ], + "77": [ + 22078, + 134 + ], + "78": [ + 14035, + 137 + ], + "79": [ + 36831, + 144 + ], + "80": [ + 37213, + 144 + ], + "81": [ + 37569, + 155 + ], + "82": [ + 32135, + 169 + ], + "83": [ + 32948, + 138 + ], + "87": [ + 6697, + 137 + ], + "88": [ + 7122, + 136 + ], + "3612": [ + 27154, + 171 + ], + "3613": [ + 36449, + 137 + ], + "3637": [ + 7957, + 141 + ], + "3639": [ + 7547, + 134 + ], + "3640": [ + 35316, + 145 + ], + "3653": [ + 8372, + 140 + ], + "3655": [ + 14949, + 119 + ], + "3657": [ + 15311, + 143 + ], + "3663": [ + 21671, + 146 + ], + "3665": [ + 22078, + 134 + ], + "3666": [ + 14524, + 141 + ], + "3667": [ + 21286, + 113 + ], + "3675": [ + 34093, + 157 + ], + "3676": [ + 35716, + 136 + ], + "3677": [ + 36449, + 137 + ], + "57416": [ + 32948, + 138 + ], + "57419": [ + 36831, + 144 + ], + "57421": [ + 37569, + 155 + ], + "57424": [ + 37213, + 144 + ], + "60999": [ + 14949, + 119 + ], + "61000": [ + 32948, + 138 + ], + "61001": [ + 15311, + 143 + ], + "61003": [ + 36831, + 144 + ], + "61005": [ + 37569, + 155 + ], + "61007": [ + 21671, + 146 + ], + "61008": [ + 37213, + 144 + ], + "61009": [ + 22078, + 134 + ], + "61010": [ + 14524, + 141 + ], + "61011": [ + 21286, + 113 + ] + } +} \ No newline at end of file diff --git a/audio/cherrymx-black-pbt/sound.ogg b/audio/cherrymx-black-pbt/sound.ogg new file mode 100644 index 0000000..d1ca801 Binary files /dev/null and b/audio/cherrymx-black-pbt/sound.ogg differ diff --git a/audio/cherrymx-blue-abs/config.json b/audio/cherrymx-blue-abs/config.json new file mode 100644 index 0000000..94319ac --- /dev/null +++ b/audio/cherrymx-blue-abs/config.json @@ -0,0 +1,465 @@ +{ + "id": "custom-sound-pack-1582707445334", + "name": "CherryMX Blue - ABS keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 1754, + 184 + ], + "2": [ + 10135, + 199 + ], + "3": [ + 10562, + 185 + ], + "4": [ + 10966, + 189 + ], + "5": [ + 11329, + 199 + ], + "6": [ + 11706, + 196 + ], + "7": [ + 12094, + 180 + ], + "8": [ + 12467, + 184 + ], + "9": [ + 12863, + 190 + ], + "10": [ + 13248, + 195 + ], + "11": [ + 13633, + 170 + ], + "12": [ + 13988, + 186 + ], + "13": [ + 14372, + 180 + ], + "14": [ + 14748, + 212 + ], + "15": [ + 16940, + 179 + ], + "16": [ + 17316, + 199 + ], + "17": [ + 17700, + 172 + ], + "18": [ + 18054, + 187 + ], + "19": [ + 18400, + 184 + ], + "20": [ + 18761, + 176 + ], + "21": [ + 19116, + 188 + ], + "22": [ + 19495, + 186 + ], + "23": [ + 19876, + 174 + ], + "24": [ + 20238, + 170 + ], + "25": [ + 20605, + 158 + ], + "26": [ + 20976, + 164 + ], + "27": [ + 21348, + 158 + ], + "28": [ + 28558, + 161 + ], + "29": [ + 35733, + 190 + ], + "30": [ + 24330, + 196 + ], + "31": [ + 24700, + 202 + ], + "32": [ + 25071, + 194 + ], + "33": [ + 25444, + 206 + ], + "34": [ + 25803, + 188 + ], + "35": [ + 26159, + 185 + ], + "36": [ + 26534, + 168 + ], + "37": [ + 26928, + 190 + ], + "38": [ + 27347, + 180 + ], + "39": [ + 27733, + 183 + ], + "40": [ + 28157, + 176 + ], + "41": [ + 9749, + 195 + ], + "42": [ + 29603, + 226 + ], + "43": [ + 21707, + 182 + ], + "44": [ + 30046, + 175 + ], + "45": [ + 30385, + 177 + ], + "46": [ + 30761, + 189 + ], + "47": [ + 31123, + 191 + ], + "48": [ + 31475, + 196 + ], + "49": [ + 31891, + 169 + ], + "50": [ + 32333, + 175 + ], + "51": [ + 33011, + 186 + ], + "52": [ + 33438, + 172 + ], + "53": [ + 33828, + 178 + ], + "54": [ + 34215, + 180 + ], + "55": [ + 7583, + 193 + ], + "56": [ + 36465, + 214 + ], + "57": [ + 36804, + 240 + ], + "58": [ + 23925, + 207 + ], + "59": [ + 2222, + 186 + ], + "60": [ + 2617, + 180 + ], + "61": [ + 3028, + 189 + ], + "62": [ + 3385, + 223 + ], + "63": [ + 3792, + 193 + ], + "64": [ + 4136, + 212 + ], + "65": [ + 4540, + 188 + ], + "66": [ + 4903, + 193 + ], + "67": [ + 5296, + 193 + ], + "68": [ + 5666, + 183 + ], + "69": [ + 6818, + 167 + ], + "70": [ + 7187, + 183 + ], + "71": [ + 15156, + 180 + ], + "72": [ + 15526, + 204 + ], + "73": [ + 15893, + 157 + ], + "74": [ + 13988, + 186 + ], + "75": [ + 22116, + 179 + ], + "76": [ + 22513, + 173 + ], + "77": [ + 22862, + 158 + ], + "78": [ + 14748, + 212 + ], + "79": [ + 39220, + 169 + ], + "80": [ + 39589, + 179 + ], + "81": [ + 39954, + 183 + ], + "82": [ + 34215, + 180 + ], + "83": [ + 34704, + 159 + ], + "87": [ + 6054, + 180 + ], + "88": [ + 6425, + 182 + ], + "3612": [ + 28558, + 161 + ], + "3613": [ + 38821, + 188 + ], + "3637": [ + 7187, + 183 + ], + "3639": [ + 6818, + 167 + ], + "3640": [ + 37730, + 184 + ], + "3653": [ + 7583, + 193 + ], + "3655": [ + 15526, + 204 + ], + "3657": [ + 15893, + 157 + ], + "3663": [ + 22513, + 173 + ], + "3665": [ + 22862, + 158 + ], + "3666": [ + 15156, + 180 + ], + "3667": [ + 22116, + 179 + ], + "3675": [ + 36115, + 205 + ], + "3676": [ + 38116, + 184 + ], + "3677": [ + 38821, + 188 + ], + "57416": [ + 34704, + 159 + ], + "57419": [ + 39220, + 169 + ], + "57421": [ + 39954, + 183 + ], + "57424": [ + 39589, + 179 + ], + "60999": [ + 15526, + 204 + ], + "61000": [ + 34704, + 159 + ], + "61001": [ + 15893, + 157 + ], + "61003": [ + 39220, + 169 + ], + "61005": [ + 39954, + 183 + ], + "61007": [ + 22513, + 173 + ], + "61008": [ + 39589, + 179 + ], + "61009": [ + 22862, + 158 + ], + "61010": [ + 15156, + 180 + ], + "61011": [ + 22116, + 179 + ] + } +} \ No newline at end of file diff --git a/audio/cherrymx-blue-abs/sound.ogg b/audio/cherrymx-blue-abs/sound.ogg new file mode 100644 index 0000000..112c361 Binary files /dev/null and b/audio/cherrymx-blue-abs/sound.ogg differ diff --git a/audio/cherrymx-blue-pbt/config.json b/audio/cherrymx-blue-pbt/config.json new file mode 100644 index 0000000..30acc7e --- /dev/null +++ b/audio/cherrymx-blue-pbt/config.json @@ -0,0 +1,465 @@ +{ + "id": "custom-sound-pack-1582707445334", + "name": "CherryMX Blue - PBT keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 1203, + 192 + ], + "2": [ + 10794, + 197 + ], + "3": [ + 11315, + 196 + ], + "4": [ + 11814, + 198 + ], + "5": [ + 12334, + 185 + ], + "6": [ + 12845, + 196 + ], + "7": [ + 13305, + 188 + ], + "8": [ + 13846, + 187 + ], + "9": [ + 14362, + 197 + ], + "10": [ + 14881, + 188 + ], + "11": [ + 15408, + 180 + ], + "12": [ + 15901, + 200 + ], + "13": [ + 16410, + 182 + ], + "14": [ + 16906, + 230 + ], + "15": [ + 19473, + 191 + ], + "16": [ + 19944, + 207 + ], + "17": [ + 20490, + 183 + ], + "18": [ + 20995, + 192 + ], + "19": [ + 21500, + 186 + ], + "20": [ + 21993, + 198 + ], + "21": [ + 22495, + 185 + ], + "22": [ + 22970, + 194 + ], + "23": [ + 23492, + 179 + ], + "24": [ + 23972, + 212 + ], + "25": [ + 24468, + 181 + ], + "26": [ + 24955, + 187 + ], + "27": [ + 25463, + 172 + ], + "28": [ + 34274, + 204 + ], + "29": [ + 42603, + 172 + ], + "30": [ + 28961, + 164 + ], + "31": [ + 29448, + 171 + ], + "32": [ + 29968, + 163 + ], + "33": [ + 30454, + 208 + ], + "34": [ + 30944, + 172 + ], + "35": [ + 31395, + 186 + ], + "36": [ + 31884, + 174 + ], + "37": [ + 32358, + 172 + ], + "38": [ + 32358, + 172 + ], + "39": [ + 33331, + 191 + ], + "40": [ + 33824, + 166 + ], + "41": [ + 10318, + 183 + ], + "42": [ + 35598, + 197 + ], + "43": [ + 25952, + 184 + ], + "44": [ + 36143, + 204 + ], + "45": [ + 36645, + 165 + ], + "46": [ + 37120, + 164 + ], + "47": [ + 37606, + 181 + ], + "48": [ + 38062, + 179 + ], + "49": [ + 38563, + 163 + ], + "50": [ + 39025, + 171 + ], + "51": [ + 39505, + 172 + ], + "52": [ + 39982, + 152 + ], + "53": [ + 40437, + 170 + ], + "54": [ + 40939, + 176 + ], + "55": [ + 9180, + 193 + ], + "56": [ + 43991, + 192 + ], + "57": [ + 49628, + 230 + ], + "58": [ + 28470, + 191 + ], + "59": [ + 1783, + 185 + ], + "60": [ + 2336, + 204 + ], + "61": [ + 2884, + 182 + ], + "62": [ + 3404, + 188 + ], + "63": [ + 3940, + 168 + ], + "64": [ + 4487, + 165 + ], + "65": [ + 5013, + 178 + ], + "66": [ + 5510, + 187 + ], + "67": [ + 6048, + 207 + ], + "68": [ + 6609, + 174 + ], + "69": [ + 8159, + 221 + ], + "70": [ + 8668, + 222 + ], + "71": [ + 17483, + 175 + ], + "72": [ + 17955, + 189 + ], + "73": [ + 18419, + 199 + ], + "74": [ + 15901, + 200 + ], + "75": [ + 26567, + 177 + ], + "76": [ + 27069, + 190 + ], + "77": [ + 27541, + 169 + ], + "78": [ + 16906, + 230 + ], + "79": [ + 47492, + 178 + ], + "80": [ + 47981, + 201 + ], + "81": [ + 48412, + 201 + ], + "82": [ + 40939, + 176 + ], + "83": [ + 41501, + 174 + ], + "87": [ + 7119, + 175 + ], + "88": [ + 7650, + 174 + ], + "3612": [ + 34274, + 204 + ], + "3613": [ + 47002, + 188 + ], + "3637": [ + 8668, + 222 + ], + "3639": [ + 8159, + 221 + ], + "3640": [ + 46069, + 202 + ], + "3653": [ + 9180, + 193 + ], + "3655": [ + 17955, + 189 + ], + "3657": [ + 18419, + 199 + ], + "3663": [ + 27069, + 190 + ], + "3665": [ + 27541, + 169 + ], + "3666": [ + 17483, + 175 + ], + "3667": [ + 26567, + 177 + ], + "3675": [ + 43435, + 155 + ], + "3676": [ + 46544, + 174 + ], + "3677": [ + 47002, + 188 + ], + "57416": [ + 41501, + 174 + ], + "57419": [ + 47492, + 178 + ], + "57421": [ + 48412, + 201 + ], + "57424": [ + 47981, + 201 + ], + "60999": [ + 17955, + 189 + ], + "61000": [ + 41501, + 174 + ], + "61001": [ + 18419, + 199 + ], + "61003": [ + 47492, + 178 + ], + "61005": [ + 48412, + 201 + ], + "61007": [ + 27069, + 190 + ], + "61008": [ + 47981, + 201 + ], + "61009": [ + 27541, + 169 + ], + "61010": [ + 17483, + 175 + ], + "61011": [ + 26567, + 177 + ] + } +} \ No newline at end of file diff --git a/audio/cherrymx-blue-pbt/sound.ogg b/audio/cherrymx-blue-pbt/sound.ogg new file mode 100644 index 0000000..440f142 Binary files /dev/null and b/audio/cherrymx-blue-pbt/sound.ogg differ diff --git a/audio/cherrymx-brown-abs/config.json b/audio/cherrymx-brown-abs/config.json new file mode 100644 index 0000000..085fa0c --- /dev/null +++ b/audio/cherrymx-brown-abs/config.json @@ -0,0 +1,465 @@ +{ + "id": "custom-sound-pack-1582656695035", + "name": "CherryMX Brown - ABS keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 1402, + 170 + ], + "2": [ + 8760, + 173 + ], + "3": [ + 9149, + 167 + ], + "4": [ + 9550, + 165 + ], + "5": [ + 9942, + 150 + ], + "6": [ + 10370, + 145 + ], + "7": [ + 10791, + 140 + ], + "8": [ + 11205, + 150 + ], + "9": [ + 11603, + 136 + ], + "10": [ + 12012, + 148 + ], + "11": [ + 12440, + 140 + ], + "12": [ + 12844, + 131 + ], + "13": [ + 13231, + 132 + ], + "14": [ + 13667, + 134 + ], + "15": [ + 15286, + 161 + ], + "16": [ + 15665, + 180 + ], + "17": [ + 16052, + 171 + ], + "18": [ + 16411, + 174 + ], + "19": [ + 16772, + 158 + ], + "20": [ + 17124, + 178 + ], + "21": [ + 17478, + 142 + ], + "22": [ + 17843, + 146 + ], + "23": [ + 18212, + 139 + ], + "24": [ + 18611, + 148 + ], + "25": [ + 19036, + 134 + ], + "26": [ + 19440, + 127 + ], + "27": [ + 19854, + 192 + ], + "28": [ + 26548, + 119 + ], + "29": [ + 32761, + 168 + ], + "30": [ + 22324, + 167 + ], + "31": [ + 22698, + 167 + ], + "32": [ + 23072, + 163 + ], + "33": [ + 23408, + 178 + ], + "34": [ + 23770, + 183 + ], + "35": [ + 24140, + 145 + ], + "36": [ + 24525, + 154 + ], + "37": [ + 24919, + 138 + ], + "38": [ + 25314, + 142 + ], + "39": [ + 25711, + 129 + ], + "40": [ + 26121, + 123 + ], + "41": [ + 8365, + 166 + ], + "42": [ + 27208, + 158 + ], + "43": [ + 20262, + 143 + ], + "44": [ + 27589, + 164 + ], + "45": [ + 27978, + 160 + ], + "46": [ + 28321, + 160 + ], + "47": [ + 28694, + 162 + ], + "48": [ + 29071, + 152 + ], + "49": [ + 29485, + 159 + ], + "50": [ + 29873, + 137 + ], + "51": [ + 30269, + 139 + ], + "52": [ + 30664, + 132 + ], + "53": [ + 31026, + 138 + ], + "54": [ + 31455, + 139 + ], + "55": [ + 7874, + 148 + ], + "56": [ + 33530, + 170 + ], + "57": [ + 37338, + 200 + ], + "58": [ + 21920, + 176 + ], + "59": [ + 1852, + 162 + ], + "60": [ + 2275, + 155 + ], + "61": [ + 2668, + 167 + ], + "62": [ + 3054, + 162 + ], + "63": [ + 3467, + 161 + ], + "64": [ + 3877, + 151 + ], + "65": [ + 4501, + 120 + ], + "66": [ + 4951, + 141 + ], + "67": [ + 5381, + 133 + ], + "68": [ + 5779, + 145 + ], + "69": [ + 7023, + 161 + ], + "70": [ + 7448, + 142 + ], + "71": [ + 14084, + 125 + ], + "72": [ + 14500, + 142 + ], + "73": [ + 14877, + 146 + ], + "74": [ + 12844, + 131 + ], + "75": [ + 20713, + 139 + ], + "76": [ + 21121, + 151 + ], + "77": [ + 21527, + 142 + ], + "78": [ + 13667, + 134 + ], + "79": [ + 35966, + 143 + ], + "80": [ + 36356, + 147 + ], + "81": [ + 36787, + 170 + ], + "82": [ + 31455, + 139 + ], + "83": [ + 32054, + 167 + ], + "87": [ + 6207, + 139 + ], + "88": [ + 6637, + 127 + ], + "3612": [ + 26548, + 119 + ], + "3613": [ + 35572, + 139 + ], + "3637": [ + 7448, + 142 + ], + "3639": [ + 7023, + 161 + ], + "3640": [ + 34354, + 157 + ], + "3653": [ + 7874, + 148 + ], + "3655": [ + 14500, + 142 + ], + "3657": [ + 14877, + 146 + ], + "3663": [ + 21121, + 151 + ], + "3665": [ + 21527, + 142 + ], + "3666": [ + 14084, + 125 + ], + "3667": [ + 20713, + 139 + ], + "3675": [ + 33157, + 170 + ], + "3676": [ + 34762, + 147 + ], + "3677": [ + 35572, + 139 + ], + "57416": [ + 32054, + 167 + ], + "57419": [ + 35966, + 143 + ], + "57421": [ + 36787, + 170 + ], + "57424": [ + 36356, + 147 + ], + "60999": [ + 14500, + 142 + ], + "61000": [ + 32054, + 167 + ], + "61001": [ + 14877, + 146 + ], + "61003": [ + 35966, + 143 + ], + "61005": [ + 36787, + 170 + ], + "61007": [ + 21121, + 151 + ], + "61008": [ + 36356, + 147 + ], + "61009": [ + 21527, + 142 + ], + "61010": [ + 14084, + 125 + ], + "61011": [ + 20713, + 139 + ] + } +} \ No newline at end of file diff --git a/audio/cherrymx-brown-abs/sound.ogg b/audio/cherrymx-brown-abs/sound.ogg new file mode 100644 index 0000000..8caf39c Binary files /dev/null and b/audio/cherrymx-brown-abs/sound.ogg differ diff --git a/audio/cherrymx-brown-pbt/config.json b/audio/cherrymx-brown-pbt/config.json new file mode 100644 index 0000000..55ab971 --- /dev/null +++ b/audio/cherrymx-brown-pbt/config.json @@ -0,0 +1,465 @@ +{ + "id": "custom-sound-pack-1582656695035", + "name": "CherryMX Brown - PBT keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 2280, + 199 + ], + "2": [ + 9444, + 185 + ], + "3": [ + 9833, + 187 + ], + "4": [ + 10185, + 194 + ], + "5": [ + 10551, + 196 + ], + "6": [ + 10899, + 194 + ], + "7": [ + 11282, + 180 + ], + "8": [ + 11623, + 188 + ], + "9": [ + 11976, + 200 + ], + "10": [ + 12337, + 197 + ], + "11": [ + 12667, + 194 + ], + "12": [ + 13058, + 191 + ], + "13": [ + 13408, + 187 + ], + "14": [ + 13765, + 184 + ], + "15": [ + 15916, + 176 + ], + "16": [ + 16284, + 150 + ], + "17": [ + 16637, + 176 + ], + "18": [ + 16964, + 190 + ], + "19": [ + 17275, + 185 + ], + "20": [ + 17613, + 196 + ], + "21": [ + 17957, + 173 + ], + "22": [ + 18301, + 190 + ], + "23": [ + 18643, + 200 + ], + "24": [ + 18994, + 178 + ], + "25": [ + 19331, + 197 + ], + "26": [ + 19671, + 171 + ], + "27": [ + 20020, + 175 + ], + "28": [ + 26703, + 181 + ], + "29": [ + 33857, + 182 + ], + "30": [ + 22869, + 198 + ], + "31": [ + 23237, + 178 + ], + "32": [ + 23586, + 187 + ], + "33": [ + 23898, + 179 + ], + "34": [ + 24237, + 185 + ], + "35": [ + 24550, + 192 + ], + "36": [ + 24917, + 188 + ], + "37": [ + 25274, + 185 + ], + "38": [ + 25625, + 183 + ], + "39": [ + 25989, + 182 + ], + "40": [ + 26335, + 180 + ], + "41": [ + 9069, + 209 + ], + "42": [ + 28109, + 180 + ], + "43": [ + 20387, + 176 + ], + "44": [ + 28550, + 167 + ], + "45": [ + 28855, + 184 + ], + "46": [ + 29557, + 204 + ], + "47": [ + 29557, + 204 + ], + "48": [ + 29909, + 179 + ], + "49": [ + 30252, + 203 + ], + "50": [ + 30605, + 184 + ], + "51": [ + 30965, + 212 + ], + "52": [ + 31315, + 176 + ], + "53": [ + 31659, + 175 + ], + "54": [ + 32015, + 184 + ], + "55": [ + 8036, + 168 + ], + "56": [ + 34551, + 175 + ], + "57": [ + 34910, + 223 + ], + "58": [ + 22560, + 181 + ], + "59": [ + 2754, + 189 + ], + "60": [ + 3155, + 180 + ], + "61": [ + 3545, + 187 + ], + "62": [ + 3913, + 183 + ], + "63": [ + 4305, + 174 + ], + "64": [ + 4666, + 187 + ], + "65": [ + 5034, + 200 + ], + "66": [ + 5433, + 187 + ], + "67": [ + 7795, + 198 + ], + "68": [ + 6146, + 191 + ], + "69": [ + 7322, + 177 + ], + "70": [ + 7699, + 178 + ], + "71": [ + 14199, + 181 + ], + "72": [ + 14522, + 196 + ], + "73": [ + 14852, + 169 + ], + "74": [ + 13058, + 191 + ], + "75": [ + 20766, + 185 + ], + "76": [ + 21102, + 187 + ], + "77": [ + 21409, + 151 + ], + "78": [ + 13765, + 184 + ], + "79": [ + 36907, + 163 + ], + "80": [ + 37267, + 170 + ], + "81": [ + 37586, + 160 + ], + "82": [ + 32015, + 184 + ], + "83": [ + 32429, + 174 + ], + "87": [ + 6560, + 196 + ], + "88": [ + 6932, + 193 + ], + "3612": [ + 26703, + 181 + ], + "3613": [ + 36571, + 182 + ], + "3637": [ + 7699, + 178 + ], + "3639": [ + 7322, + 177 + ], + "3640": [ + 35492, + 157 + ], + "3653": [ + 8036, + 168 + ], + "3655": [ + 14522, + 196 + ], + "3657": [ + 14852, + 169 + ], + "3663": [ + 21102, + 187 + ], + "3665": [ + 21409, + 151 + ], + "3666": [ + 14199, + 181 + ], + "3667": [ + 20766, + 185 + ], + "3675": [ + 34181, + 177 + ], + "3676": [ + 35878, + 164 + ], + "3677": [ + 36571, + 182 + ], + "57416": [ + 32429, + 174 + ], + "57419": [ + 36907, + 163 + ], + "57421": [ + 37586, + 160 + ], + "57424": [ + 37267, + 170 + ], + "60999": [ + 14522, + 196 + ], + "61000": [ + 32429, + 174 + ], + "61001": [ + 14852, + 169 + ], + "61003": [ + 36907, + 163 + ], + "61005": [ + 37586, + 160 + ], + "61007": [ + 21102, + 187 + ], + "61008": [ + 37267, + 170 + ], + "61009": [ + 21409, + 151 + ], + "61010": [ + 14199, + 181 + ], + "61011": [ + 20766, + 185 + ] + } +} \ No newline at end of file diff --git a/audio/cherrymx-brown-pbt/sound.ogg b/audio/cherrymx-brown-pbt/sound.ogg new file mode 100644 index 0000000..bba9c3b Binary files /dev/null and b/audio/cherrymx-brown-pbt/sound.ogg differ diff --git a/audio/cherrymx-red-abs/config.json b/audio/cherrymx-red-abs/config.json new file mode 100644 index 0000000..ea638b5 --- /dev/null +++ b/audio/cherrymx-red-abs/config.json @@ -0,0 +1,465 @@ +{ + "id": "custom-sound-pack-1582707445334", + "name": "CherryMX Red - ABS keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 2464, + 170 + ], + "2": [ + 11371, + 178 + ], + "3": [ + 11846, + 169 + ], + "4": [ + 12302, + 194 + ], + "5": [ + 12746, + 214 + ], + "6": [ + 13183, + 174 + ], + "7": [ + 13619, + 183 + ], + "8": [ + 14064, + 177 + ], + "9": [ + 14504, + 188 + ], + "10": [ + 14956, + 166 + ], + "11": [ + 15408, + 211 + ], + "12": [ + 15823, + 192 + ], + "13": [ + 16291, + 181 + ], + "14": [ + 16727, + 227 + ], + "15": [ + 19161, + 185 + ], + "16": [ + 19606, + 168 + ], + "17": [ + 20024, + 194 + ], + "18": [ + 20478, + 175 + ], + "19": [ + 20892, + 171 + ], + "20": [ + 21250, + 177 + ], + "21": [ + 21670, + 186 + ], + "22": [ + 22098, + 197 + ], + "23": [ + 22601, + 174 + ], + "24": [ + 23102, + 181 + ], + "25": [ + 23594, + 186 + ], + "26": [ + 24062, + 150 + ], + "27": [ + 24507, + 192 + ], + "28": [ + 32833, + 190 + ], + "29": [ + 40730, + 163 + ], + "30": [ + 27942, + 151 + ], + "31": [ + 28366, + 177 + ], + "32": [ + 28771, + 168 + ], + "33": [ + 29171, + 201 + ], + "34": [ + 29577, + 175 + ], + "35": [ + 29986, + 189 + ], + "36": [ + 30413, + 183 + ], + "37": [ + 30821, + 196 + ], + "38": [ + 31527, + 243 + ], + "39": [ + 32024, + 192 + ], + "40": [ + 32459, + 193 + ], + "41": [ + 10927, + 181 + ], + "42": [ + 34277, + 212 + ], + "43": [ + 24956, + 155 + ], + "44": [ + 34773, + 192 + ], + "45": [ + 35220, + 199 + ], + "46": [ + 35671, + 155 + ], + "47": [ + 36089, + 158 + ], + "48": [ + 36453, + 180 + ], + "49": [ + 36825, + 190 + ], + "50": [ + 37239, + 189 + ], + "51": [ + 37706, + 168 + ], + "52": [ + 38150, + 177 + ], + "53": [ + 38597, + 191 + ], + "54": [ + 39015, + 200 + ], + "55": [ + 9720, + 182 + ], + "56": [ + 41606, + 182 + ], + "57": [ + 42071, + 230 + ], + "58": [ + 27462, + 179 + ], + "59": [ + 3016, + 182 + ], + "60": [ + 3534, + 177 + ], + "61": [ + 4003, + 180 + ], + "62": [ + 3924, + 200 + ], + "63": [ + 4472, + 188 + ], + "64": [ + 4988, + 179 + ], + "65": [ + 5476, + 168 + ], + "66": [ + 5956, + 183 + ], + "67": [ + 6419, + 208 + ], + "68": [ + 6927, + 202 + ], + "69": [ + 8367, + 180 + ], + "70": [ + 9329, + 184 + ], + "71": [ + 17343, + 177 + ], + "72": [ + 17757, + 181 + ], + "73": [ + 18135, + 163 + ], + "74": [ + 15823, + 192 + ], + "75": [ + 25449, + 166 + ], + "76": [ + 25889, + 175 + ], + "77": [ + 26298, + 141 + ], + "78": [ + 16727, + 227 + ], + "79": [ + 44811, + 202 + ], + "80": [ + 45226, + 203 + ], + "81": [ + 45618, + 197 + ], + "82": [ + 39015, + 200 + ], + "83": [ + 39528, + 180 + ], + "87": [ + 7434, + 188 + ], + "88": [ + 7908, + 182 + ], + "3612": [ + 32833, + 190 + ], + "3613": [ + 44374, + 197 + ], + "3637": [ + 9329, + 184 + ], + "3639": [ + 8367, + 180 + ], + "3640": [ + 43033, + 175 + ], + "3653": [ + 9720, + 182 + ], + "3655": [ + 17757, + 181 + ], + "3657": [ + 18135, + 163 + ], + "3663": [ + 25889, + 175 + ], + "3665": [ + 26298, + 141 + ], + "3666": [ + 17343, + 177 + ], + "3667": [ + 25449, + 166 + ], + "3675": [ + 41166, + 216 + ], + "3676": [ + 43497, + 203 + ], + "3677": [ + 44374, + 197 + ], + "57416": [ + 39528, + 180 + ], + "57419": [ + 44811, + 202 + ], + "57421": [ + 45618, + 197 + ], + "57424": [ + 45226, + 203 + ], + "60999": [ + 17757, + 181 + ], + "61000": [ + 39528, + 180 + ], + "61001": [ + 18135, + 163 + ], + "61003": [ + 44811, + 202 + ], + "61005": [ + 45618, + 197 + ], + "61007": [ + 25889, + 175 + ], + "61008": [ + 45226, + 203 + ], + "61009": [ + 26298, + 141 + ], + "61010": [ + 17343, + 177 + ], + "61011": [ + 25449, + 166 + ] + } +} \ No newline at end of file diff --git a/audio/cherrymx-red-abs/sound.ogg b/audio/cherrymx-red-abs/sound.ogg new file mode 100644 index 0000000..23f528e Binary files /dev/null and b/audio/cherrymx-red-abs/sound.ogg differ diff --git a/audio/cherrymx-red-pbt/config.json b/audio/cherrymx-red-pbt/config.json new file mode 100644 index 0000000..b387cde --- /dev/null +++ b/audio/cherrymx-red-pbt/config.json @@ -0,0 +1,465 @@ +{ + "id": "custom-sound-pack-1582707445334", + "name": "CherryMX Red - PBT keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 3339, + 187 + ], + "2": [ + 11673, + 137 + ], + "3": [ + 12175, + 143 + ], + "4": [ + 12601, + 185 + ], + "5": [ + 13056, + 152 + ], + "6": [ + 13512, + 150 + ], + "7": [ + 13919, + 160 + ], + "8": [ + 14411, + 147 + ], + "9": [ + 14853, + 182 + ], + "10": [ + 15330, + 162 + ], + "11": [ + 15771, + 182 + ], + "12": [ + 16215, + 158 + ], + "13": [ + 16662, + 170 + ], + "14": [ + 17067, + 207 + ], + "15": [ + 19327, + 196 + ], + "16": [ + 19717, + 153 + ], + "17": [ + 20144, + 159 + ], + "18": [ + 20556, + 150 + ], + "19": [ + 20966, + 158 + ], + "20": [ + 21371, + 193 + ], + "21": [ + 21836, + 186 + ], + "22": [ + 22303, + 163 + ], + "23": [ + 22724, + 198 + ], + "24": [ + 23198, + 170 + ], + "25": [ + 23643, + 168 + ], + "26": [ + 24072, + 179 + ], + "27": [ + 24527, + 175 + ], + "28": [ + 32734, + 230 + ], + "29": [ + 40191, + 178 + ], + "30": [ + 27803, + 158 + ], + "31": [ + 28294, + 151 + ], + "32": [ + 28716, + 178 + ], + "33": [ + 29158, + 182 + ], + "34": [ + 29563, + 156 + ], + "35": [ + 30053, + 155 + ], + "36": [ + 30477, + 148 + ], + "37": [ + 30945, + 155 + ], + "38": [ + 31372, + 172 + ], + "39": [ + 31812, + 188 + ], + "40": [ + 32290, + 200 + ], + "41": [ + 11265, + 179 + ], + "42": [ + 33773, + 225 + ], + "43": [ + 24965, + 196 + ], + "44": [ + 34211, + 139 + ], + "45": [ + 34623, + 154 + ], + "46": [ + 34981, + 174 + ], + "47": [ + 35448, + 156 + ], + "48": [ + 35870, + 188 + ], + "49": [ + 36310, + 170 + ], + "50": [ + 36715, + 188 + ], + "51": [ + 37150, + 165 + ], + "52": [ + 37577, + 177 + ], + "53": [ + 38025, + 173 + ], + "54": [ + 38477, + 180 + ], + "55": [ + 10319, + 214 + ], + "56": [ + 40985, + 175 + ], + "57": [ + 47621, + 300 + ], + "58": [ + 27372, + 190 + ], + "59": [ + 3878, + 151 + ], + "60": [ + 4347, + 169 + ], + "61": [ + 4825, + 166 + ], + "62": [ + 5272, + 151 + ], + "63": [ + 5737, + 157 + ], + "64": [ + 6174, + 1194 + ], + "65": [ + 6635, + 198 + ], + "66": [ + 7088, + 186 + ], + "67": [ + 7578, + 195 + ], + "68": [ + 7989, + 222 + ], + "69": [ + 9455, + 168 + ], + "70": [ + 9935, + 145 + ], + "71": [ + 17568, + 158 + ], + "72": [ + 18000, + 195 + ], + "73": [ + 18413, + 166 + ], + "74": [ + 16215, + 158 + ], + "75": [ + 25461, + 177 + ], + "76": [ + 25888, + 193 + ], + "77": [ + 26353, + 210 + ], + "78": [ + 17067, + 207 + ], + "79": [ + 44074, + 175 + ], + "80": [ + 44511, + 178 + ], + "81": [ + 44989, + 179 + ], + "82": [ + 38477, + 180 + ], + "83": [ + 39044, + 186 + ], + "87": [ + 8467, + 205 + ], + "88": [ + 8958, + 190 + ], + "3612": [ + 32734, + 230 + ], + "3613": [ + 43623, + 175 + ], + "3637": [ + 9935, + 145 + ], + "3639": [ + 9455, + 168 + ], + "3640": [ + 42367, + 194 + ], + "3653": [ + 10319, + 214 + ], + "3655": [ + 18000, + 195 + ], + "3657": [ + 18413, + 166 + ], + "3663": [ + 25888, + 193 + ], + "3665": [ + 26353, + 210 + ], + "3666": [ + 17568, + 158 + ], + "3667": [ + 25461, + 177 + ], + "3675": [ + 40588, + 184 + ], + "3676": [ + 43196, + 203 + ], + "3677": [ + 43623, + 175 + ], + "57416": [ + 39044, + 186 + ], + "57419": [ + 44074, + 175 + ], + "57421": [ + 44989, + 179 + ], + "57424": [ + 44511, + 178 + ], + "60999": [ + 18000, + 195 + ], + "61000": [ + 39044, + 186 + ], + "61001": [ + 18413, + 166 + ], + "61003": [ + 44074, + 175 + ], + "61005": [ + 44989, + 179 + ], + "61007": [ + 25888, + 193 + ], + "61008": [ + 44511, + 178 + ], + "61009": [ + 26353, + 210 + ], + "61010": [ + 17568, + 158 + ], + "61011": [ + 25461, + 177 + ] + } +} \ No newline at end of file diff --git a/audio/cherrymx-red-pbt/sound.ogg b/audio/cherrymx-red-pbt/sound.ogg new file mode 100644 index 0000000..7c5e8ee Binary files /dev/null and b/audio/cherrymx-red-pbt/sound.ogg differ diff --git a/audio/cream-travel/config.json b/audio/cream-travel/config.json new file mode 100644 index 0000000..9628888 --- /dev/null +++ b/audio/cream-travel/config.json @@ -0,0 +1,16 @@ +{ + "id": "custom-sound-pack-1720300926821", + "name": "Full Creamy Goodness", + "key_define_type": "multi", + "sound": "press/GENERIC_R{0-4}.mp3", + "soundup": "release/GENERIC.mp3", + "defines": { + "14": "press/BACKSPACE.mp3", + "14-up": "release/BACKSPACE.mp3", + "28": "press/ENTER.mp3", + "28-up": "release/ENTER.mp3", + "57": "press/SPACE.mp3", + "57-up": "release/SPACE.mp3" + }, + "version": 2 +} \ No newline at end of file diff --git a/audio/cream-travel/press/BACKSPACE.mp3 b/audio/cream-travel/press/BACKSPACE.mp3 new file mode 100644 index 0000000..1a78cab Binary files /dev/null and b/audio/cream-travel/press/BACKSPACE.mp3 differ diff --git a/audio/cream-travel/press/ENTER.mp3 b/audio/cream-travel/press/ENTER.mp3 new file mode 100644 index 0000000..e49e835 Binary files /dev/null and b/audio/cream-travel/press/ENTER.mp3 differ diff --git a/audio/cream-travel/press/GENERIC_R0.mp3 b/audio/cream-travel/press/GENERIC_R0.mp3 new file mode 100644 index 0000000..62c7d84 Binary files /dev/null and b/audio/cream-travel/press/GENERIC_R0.mp3 differ diff --git a/audio/cream-travel/press/GENERIC_R1.mp3 b/audio/cream-travel/press/GENERIC_R1.mp3 new file mode 100644 index 0000000..2ccc7f8 Binary files /dev/null and b/audio/cream-travel/press/GENERIC_R1.mp3 differ diff --git a/audio/cream-travel/press/GENERIC_R2.mp3 b/audio/cream-travel/press/GENERIC_R2.mp3 new file mode 100644 index 0000000..f24ba50 Binary files /dev/null and b/audio/cream-travel/press/GENERIC_R2.mp3 differ diff --git a/audio/cream-travel/press/GENERIC_R3.mp3 b/audio/cream-travel/press/GENERIC_R3.mp3 new file mode 100644 index 0000000..6e647c5 Binary files /dev/null and b/audio/cream-travel/press/GENERIC_R3.mp3 differ diff --git a/audio/cream-travel/press/GENERIC_R4.mp3 b/audio/cream-travel/press/GENERIC_R4.mp3 new file mode 100644 index 0000000..b3c9544 Binary files /dev/null and b/audio/cream-travel/press/GENERIC_R4.mp3 differ diff --git a/audio/cream-travel/press/SPACE.mp3 b/audio/cream-travel/press/SPACE.mp3 new file mode 100644 index 0000000..fb7fb8e Binary files /dev/null and b/audio/cream-travel/press/SPACE.mp3 differ diff --git a/audio/cream-travel/release/BACKSPACE.mp3 b/audio/cream-travel/release/BACKSPACE.mp3 new file mode 100644 index 0000000..3ad32b9 Binary files /dev/null and b/audio/cream-travel/release/BACKSPACE.mp3 differ diff --git a/audio/cream-travel/release/ENTER.mp3 b/audio/cream-travel/release/ENTER.mp3 new file mode 100644 index 0000000..defbcbb Binary files /dev/null and b/audio/cream-travel/release/ENTER.mp3 differ diff --git a/audio/cream-travel/release/GENERIC.mp3 b/audio/cream-travel/release/GENERIC.mp3 new file mode 100644 index 0000000..4da558a Binary files /dev/null and b/audio/cream-travel/release/GENERIC.mp3 differ diff --git a/audio/cream-travel/release/SPACE.mp3 b/audio/cream-travel/release/SPACE.mp3 new file mode 100644 index 0000000..777c5ac Binary files /dev/null and b/audio/cream-travel/release/SPACE.mp3 differ diff --git a/audio/eg-crystal-purple/config.json b/audio/eg-crystal-purple/config.json new file mode 100644 index 0000000..1961af5 --- /dev/null +++ b/audio/eg-crystal-purple/config.json @@ -0,0 +1,469 @@ +{ + "id": "custom-sound-pack-1605530100183", + "name": "EG Crystal Purple", + "key_define_type": "single", + "includes_numpad": false, + "sound": "purple.ogg", + "defines": { + "1": [ + 1088, + 118 + ], + "2": [ + 1839, + 140 + ], + "3": [ + 2207, + 143 + ], + "4": [ + 2507, + 143 + ], + "5": [ + 2809, + 148 + ], + "6": [ + 3099, + 141 + ], + "7": [ + 3408, + 134 + ], + "8": [ + 3716, + 147 + ], + "9": [ + 4017, + 139 + ], + "10": [ + 4352, + 144 + ], + "11": [ + 4657, + 126 + ], + "12": [ + 4946, + 134 + ], + "13": [ + 5250, + 133 + ], + "14": [ + 5566, + 143 + ], + "15": [ + 6792, + 157 + ], + "16": [ + 7080, + 142 + ], + "17": [ + 7367, + 134 + ], + "18": [ + 7680, + 130 + ], + "19": [ + 7973, + 133 + ], + "20": [ + 8259, + 134 + ], + "21": [ + 8549, + 135 + ], + "22": [ + 8838, + 135 + ], + "23": [ + 9103, + 150 + ], + "24": [ + 9405, + 132 + ], + "25": [ + 9703, + 131 + ], + "26": [ + 10015, + 144 + ], + "27": [ + 10397, + 112 + ], + "28": [ + 15361, + 130 + ], + "29": [ + 21408, + 128 + ], + "30": [ + 12061, + 129 + ], + "31": [ + 12339, + 121 + ], + "32": [ + 12632, + 127 + ], + "33": [ + 12916, + 119 + ], + "34": [ + 13227, + 121 + ], + "35": [ + 13526, + 124 + ], + "36": [ + 13819, + 131 + ], + "37": [ + 14115, + 113 + ], + "38": [ + 14406, + 123 + ], + "39": [ + 14711, + 128 + ], + "40": [ + 15022, + 133 + ], + "41": [ + 1088, + 118 + ], + "42": [ + 16600, + 136 + ], + "43": [ + 10718, + 127 + ], + "44": [ + 16879, + 128 + ], + "45": [ + 17196, + 132 + ], + "46": [ + 17503, + 113 + ], + "47": [ + 17788, + 115 + ], + "48": [ + 18069, + 117 + ], + "49": [ + 18349, + 130 + ], + "50": [ + 18653, + 123 + ], + "51": [ + 18964, + 119 + ], + "52": [ + 19282, + 124 + ], + "53": [ + 19594, + 120 + ], + "54": [ + 19966, + 130 + ], + "55": [ + 10398, + 106 + ], + "56": [ + 21956, + 134 + ], + "57": [ + 22501, + 164 + ], + "58": [ + 11797, + 140 + ], + "59": [ + 1837, + 150 + ], + "60": [ + 2210, + 145 + ], + "61": [ + 2503, + 154 + ], + "62": [ + 2806, + 149 + ], + "63": [ + 3099, + 151 + ], + "64": [ + 3405, + 151 + ], + "65": [ + 3712, + 150 + ], + "66": [ + 4015, + 146 + ], + "67": [ + 4354, + 140 + ], + "68": [ + 4650, + 143 + ], + "69": [ + 9700, + 127 + ], + "70": [ + 2205, + 151 + ], + "71": [ + 11070, + 112 + ], + "72": [ + 12338, + 115 + ], + "73": [ + 12634, + 120 + ], + "74": [ + 10718, + 123 + ], + "75": [ + 12912, + 115 + ], + "76": [ + 13226, + 119 + ], + "77": [ + 13529, + 117 + ], + "78": [ + 5567, + 141 + ], + "79": [ + 13814, + 141 + ], + "80": [ + 14114, + 117 + ], + "81": [ + 14401, + 127 + ], + "82": [ + 16592, + 164 + ], + "83": [ + 14715, + 123 + ], + "87": [ + 4941, + 142 + ], + "88": [ + 5249, + 149 + ], + "91": null, + "92": null, + "93": null, + "3597": null, + "3612": [ + 11798, + 129 + ], + "3613": [ + 23720, + 119 + ], + "3637": [ + 10015, + 139 + ], + "3639": [ + 1837, + 151 + ], + "3640": [ + 23148, + 122 + ], + "3653": [ + 2499, + 153 + ], + "3655": [ + 7679, + 127 + ], + "3657": [ + 7975, + 123 + ], + "3663": [ + 9110, + 133 + ], + "3665": [ + 9405, + 125 + ], + "3666": [ + 7369, + 119 + ], + "3667": [ + 8839, + 134 + ], + "3675": [ + 21677, + 127 + ], + "3676": [ + 23425, + 120 + ], + "3677": [ + 23425, + 120 + ], + "57416": [ + 20381, + 137 + ], + "57419": [ + 23982, + 128 + ], + "57421": [ + 24215, + 143 + ], + "57424": [ + 24223, + 134 + ], + "60999": [ + 7679, + 127 + ], + "61000": [ + 20381, + 137 + ], + "61001": [ + 7975, + 123 + ], + "61003": [ + 23982, + 128 + ], + "61005": [ + 24215, + 143 + ], + "61007": [ + 9110, + 133 + ], + "61008": [ + 24223, + 134 + ], + "61009": [ + 9405, + 125 + ], + "61010": [ + 7369, + 119 + ], + "61011": [ + 8839, + 134 + ] + } +} \ No newline at end of file diff --git a/audio/eg-crystal-purple/purple.ogg b/audio/eg-crystal-purple/purple.ogg new file mode 100644 index 0000000..c531357 Binary files /dev/null and b/audio/eg-crystal-purple/purple.ogg differ diff --git a/audio/eg-oreo/config.json b/audio/eg-oreo/config.json new file mode 100644 index 0000000..ddaebb1 --- /dev/null +++ b/audio/eg-oreo/config.json @@ -0,0 +1,469 @@ +{ + "id": "custom-sound-pack-1605532336205", + "name": "EG Oreo", + "key_define_type": "single", + "includes_numpad": false, + "sound": "oreo.ogg", + "defines": { + "1": [ + 971, + 142 + ], + "2": [ + 1276, + 115 + ], + "3": [ + 1604, + 122 + ], + "4": [ + 1929, + 122 + ], + "5": [ + 2237, + 134 + ], + "6": [ + 2571, + 120 + ], + "7": [ + 2869, + 122 + ], + "8": [ + 3177, + 130 + ], + "9": [ + 3482, + 110 + ], + "10": [ + 3782, + 121 + ], + "11": [ + 4077, + 128 + ], + "12": [ + 4376, + 120 + ], + "13": [ + 4673, + 123 + ], + "14": [ + 4991, + 131 + ], + "15": [ + 5968, + 123 + ], + "16": [ + 6221, + 114 + ], + "17": [ + 6515, + 120 + ], + "18": [ + 6823, + 113 + ], + "19": [ + 7112, + 110 + ], + "20": [ + 7412, + 107 + ], + "21": [ + 7716, + 112 + ], + "22": [ + 8012, + 118 + ], + "23": [ + 8326, + 112 + ], + "24": [ + 8623, + 111 + ], + "25": [ + 8932, + 112 + ], + "26": [ + 9246, + 117 + ], + "27": [ + 9586, + 118 + ], + "28": [ + 14603, + 116 + ], + "29": [ + 20804, + 118 + ], + "30": [ + 11171, + 109 + ], + "31": [ + 11462, + 120 + ], + "32": [ + 11784, + 106 + ], + "33": [ + 12080, + 104 + ], + "34": [ + 12400, + 117 + ], + "35": [ + 12715, + 110 + ], + "36": [ + 13014, + 109 + ], + "37": [ + 13333, + 116 + ], + "38": [ + 13638, + 113 + ], + "39": [ + 13967, + 106 + ], + "40": [ + 14280, + 101 + ], + "41": [ + 972, + 131 + ], + "42": [ + 15759, + 123 + ], + "43": [ + 9915, + 121 + ], + "44": [ + 16203, + 127 + ], + "45": [ + 16533, + 117 + ], + "46": [ + 16843, + 111 + ], + "47": [ + 17166, + 103 + ], + "48": [ + 17455, + 109 + ], + "49": [ + 17767, + 108 + ], + "50": [ + 18088, + 104 + ], + "51": [ + 18402, + 104 + ], + "52": [ + 18720, + 110 + ], + "53": [ + 19044, + 108 + ], + "54": [ + 19375, + 124 + ], + "55": [ + 6822, + 116 + ], + "56": [ + 21399, + 119 + ], + "57": [ + 24626, + 143 + ], + "58": [ + 10885, + 126 + ], + "59": [ + 1272, + 126 + ], + "60": [ + 1603, + 125 + ], + "61": [ + 1924, + 128 + ], + "62": [ + 2240, + 126 + ], + "63": [ + 2566, + 126 + ], + "64": [ + 2869, + 122 + ], + "65": [ + 3179, + 131 + ], + "66": [ + 3480, + 115 + ], + "67": [ + 3782, + 124 + ], + "68": [ + 4076, + 126 + ], + "69": [ + 6216, + 122 + ], + "70": [ + 12080, + 103 + ], + "71": [ + 8322, + 117 + ], + "72": [ + 8620, + 113 + ], + "73": [ + 8931, + 114 + ], + "74": [ + 7114, + 109 + ], + "75": [ + 9242, + 122 + ], + "76": [ + 9580, + 131 + ], + "77": [ + 9913, + 118 + ], + "78": [ + 7409, + 117 + ], + "79": [ + 10228, + 118 + ], + "80": [ + 11173, + 110 + ], + "81": [ + 11463, + 118 + ], + "82": [ + 8012, + 115 + ], + "83": [ + 12079, + 112 + ], + "87": [ + 4377, + 120 + ], + "88": [ + 4988, + 135 + ], + "91": null, + "92": null, + "93": null, + "3597": null, + "3612": [ + 7715, + 112 + ], + "3613": [ + 23519, + 127 + ], + "3637": [ + 6511, + 126 + ], + "3639": [ + 11782, + 110 + ], + "3640": [ + 22658, + 126 + ], + "3653": [ + 12715, + 106 + ], + "3655": [ + 13328, + 126 + ], + "3657": [ + 13641, + 107 + ], + "3663": [ + 14278, + 104 + ], + "3665": [ + 14602, + 120 + ], + "3666": [ + 13016, + 108 + ], + "3667": [ + 13964, + 113 + ], + "3675": [ + 21097, + 129 + ], + "3676": [ + 22917, + 129 + ], + "3677": [ + 23232, + 126 + ], + "57416": [ + 19720, + 122 + ], + "57419": [ + 23797, + 119 + ], + "57421": [ + 22657, + 129 + ], + "57424": [ + 24087, + 119 + ], + "60999": [ + 13328, + 126 + ], + "61000": [ + 19720, + 122 + ], + "61001": [ + 13641, + 107 + ], + "61003": [ + 23797, + 119 + ], + "61005": [ + 22657, + 129 + ], + "61007": [ + 14278, + 104 + ], + "61008": [ + 24087, + 119 + ], + "61009": [ + 14602, + 120 + ], + "61010": [ + 13016, + 108 + ], + "61011": [ + 13964, + 113 + ] + } +} diff --git a/audio/eg-oreo/oreo.ogg b/audio/eg-oreo/oreo.ogg new file mode 100644 index 0000000..b9903dd Binary files /dev/null and b/audio/eg-oreo/oreo.ogg differ diff --git a/audio/holy-pandas/BACKSPACE.mp3 b/audio/holy-pandas/BACKSPACE.mp3 new file mode 100644 index 0000000..4bfa1c7 Binary files /dev/null and b/audio/holy-pandas/BACKSPACE.mp3 differ diff --git a/audio/holy-pandas/ENTER.mp3 b/audio/holy-pandas/ENTER.mp3 new file mode 100644 index 0000000..ee1d781 Binary files /dev/null and b/audio/holy-pandas/ENTER.mp3 differ diff --git a/audio/holy-pandas/GENERIC_R0.mp3 b/audio/holy-pandas/GENERIC_R0.mp3 new file mode 100644 index 0000000..031b89b Binary files /dev/null and b/audio/holy-pandas/GENERIC_R0.mp3 differ diff --git a/audio/holy-pandas/GENERIC_R1.mp3 b/audio/holy-pandas/GENERIC_R1.mp3 new file mode 100644 index 0000000..2a23c63 Binary files /dev/null and b/audio/holy-pandas/GENERIC_R1.mp3 differ diff --git a/audio/holy-pandas/GENERIC_R2.mp3 b/audio/holy-pandas/GENERIC_R2.mp3 new file mode 100644 index 0000000..b31d2fb Binary files /dev/null and b/audio/holy-pandas/GENERIC_R2.mp3 differ diff --git a/audio/holy-pandas/GENERIC_R3.mp3 b/audio/holy-pandas/GENERIC_R3.mp3 new file mode 100644 index 0000000..a836791 Binary files /dev/null and b/audio/holy-pandas/GENERIC_R3.mp3 differ diff --git a/audio/holy-pandas/GENERIC_R4.mp3 b/audio/holy-pandas/GENERIC_R4.mp3 new file mode 100644 index 0000000..96297b3 Binary files /dev/null and b/audio/holy-pandas/GENERIC_R4.mp3 differ diff --git a/audio/holy-pandas/LICENSE b/audio/holy-pandas/LICENSE new file mode 100644 index 0000000..69da5f1 --- /dev/null +++ b/audio/holy-pandas/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) Thomas Lai + +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: + +The above copyright notice and this permission notice 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. diff --git a/audio/holy-pandas/README.md b/audio/holy-pandas/README.md new file mode 100644 index 0000000..a88fd1c --- /dev/null +++ b/audio/holy-pandas/README.md @@ -0,0 +1 @@ +This content pack comes from https://github.com/tplai/kbsim diff --git a/audio/holy-pandas/SPACE.mp3 b/audio/holy-pandas/SPACE.mp3 new file mode 100644 index 0000000..326dcca Binary files /dev/null and b/audio/holy-pandas/SPACE.mp3 differ diff --git a/audio/holy-pandas/config.json b/audio/holy-pandas/config.json new file mode 100644 index 0000000..b26f60c --- /dev/null +++ b/audio/holy-pandas/config.json @@ -0,0 +1,16 @@ +{ + "id": "custom-sound-pack-1720300926819", + "name": "pandas", + "key_define_type": "multi", + "sound": "GENERIC_R{0-4}.mp3", + "soundup": "release/GENERIC.mp3", + "defines": { + "14": "BACKSPACE.mp3", + "14-up": "release/BACKSPACE.mp3", + "28": "ENTER.mp3", + "28-up": "release/ENTER.mp3", + "57": "SPACE.mp3", + "57-up": "release/SPACE.mp3" + }, + "version": 2 +} diff --git a/audio/holy-pandas/release/BACKSPACE.mp3 b/audio/holy-pandas/release/BACKSPACE.mp3 new file mode 100644 index 0000000..f4df8a0 Binary files /dev/null and b/audio/holy-pandas/release/BACKSPACE.mp3 differ diff --git a/audio/holy-pandas/release/ENTER.mp3 b/audio/holy-pandas/release/ENTER.mp3 new file mode 100644 index 0000000..ca6618a Binary files /dev/null and b/audio/holy-pandas/release/ENTER.mp3 differ diff --git a/audio/holy-pandas/release/GENERIC.mp3 b/audio/holy-pandas/release/GENERIC.mp3 new file mode 100644 index 0000000..3897e0d Binary files /dev/null and b/audio/holy-pandas/release/GENERIC.mp3 differ diff --git a/audio/holy-pandas/release/SPACE.mp3 b/audio/holy-pandas/release/SPACE.mp3 new file mode 100644 index 0000000..556c2a0 Binary files /dev/null and b/audio/holy-pandas/release/SPACE.mp3 differ diff --git a/audio/mxblack-travel/config.json b/audio/mxblack-travel/config.json new file mode 100644 index 0000000..58ef879 --- /dev/null +++ b/audio/mxblack-travel/config.json @@ -0,0 +1,16 @@ +{ + "id": "custom-sound-pack-1720300926821", + "name": "MX Black - Full Travel", + "key_define_type": "multi", + "sound": "press/GENERIC_R{0-4}.mp3", + "soundup": "release/GENERIC.mp3", + "defines": { + "14": "press/BACKSPACE.mp3", + "14-up": "release/BACKSPACE.mp3", + "28": "press/ENTER.mp3", + "28-up": "release/ENTER.mp3", + "57": "press/SPACE.mp3", + "57-up": "release/SPACE.mp3" + }, + "version": 2 +} \ No newline at end of file diff --git a/audio/mxblack-travel/press/BACKSPACE.mp3 b/audio/mxblack-travel/press/BACKSPACE.mp3 new file mode 100644 index 0000000..23258bb Binary files /dev/null and b/audio/mxblack-travel/press/BACKSPACE.mp3 differ diff --git a/audio/mxblack-travel/press/ENTER.mp3 b/audio/mxblack-travel/press/ENTER.mp3 new file mode 100644 index 0000000..9956074 Binary files /dev/null and b/audio/mxblack-travel/press/ENTER.mp3 differ diff --git a/audio/mxblack-travel/press/GENERIC_R0.mp3 b/audio/mxblack-travel/press/GENERIC_R0.mp3 new file mode 100644 index 0000000..8a47132 Binary files /dev/null and b/audio/mxblack-travel/press/GENERIC_R0.mp3 differ diff --git a/audio/mxblack-travel/press/GENERIC_R1.mp3 b/audio/mxblack-travel/press/GENERIC_R1.mp3 new file mode 100644 index 0000000..5d8a7ce Binary files /dev/null and b/audio/mxblack-travel/press/GENERIC_R1.mp3 differ diff --git a/audio/mxblack-travel/press/GENERIC_R2.mp3 b/audio/mxblack-travel/press/GENERIC_R2.mp3 new file mode 100644 index 0000000..7e4e373 Binary files /dev/null and b/audio/mxblack-travel/press/GENERIC_R2.mp3 differ diff --git a/audio/mxblack-travel/press/GENERIC_R3.mp3 b/audio/mxblack-travel/press/GENERIC_R3.mp3 new file mode 100644 index 0000000..1d2de16 Binary files /dev/null and b/audio/mxblack-travel/press/GENERIC_R3.mp3 differ diff --git a/audio/mxblack-travel/press/GENERIC_R4.mp3 b/audio/mxblack-travel/press/GENERIC_R4.mp3 new file mode 100644 index 0000000..f8851a8 Binary files /dev/null and b/audio/mxblack-travel/press/GENERIC_R4.mp3 differ diff --git a/audio/mxblack-travel/press/SPACE.mp3 b/audio/mxblack-travel/press/SPACE.mp3 new file mode 100644 index 0000000..32c6751 Binary files /dev/null and b/audio/mxblack-travel/press/SPACE.mp3 differ diff --git a/audio/mxblack-travel/release/BACKSPACE.mp3 b/audio/mxblack-travel/release/BACKSPACE.mp3 new file mode 100644 index 0000000..02e0d0e Binary files /dev/null and b/audio/mxblack-travel/release/BACKSPACE.mp3 differ diff --git a/audio/mxblack-travel/release/ENTER.mp3 b/audio/mxblack-travel/release/ENTER.mp3 new file mode 100644 index 0000000..576e0d9 Binary files /dev/null and b/audio/mxblack-travel/release/ENTER.mp3 differ diff --git a/audio/mxblack-travel/release/GENERIC.mp3 b/audio/mxblack-travel/release/GENERIC.mp3 new file mode 100644 index 0000000..a3c6404 Binary files /dev/null and b/audio/mxblack-travel/release/GENERIC.mp3 differ diff --git a/audio/mxblack-travel/release/SPACE.mp3 b/audio/mxblack-travel/release/SPACE.mp3 new file mode 100644 index 0000000..1ecc139 Binary files /dev/null and b/audio/mxblack-travel/release/SPACE.mp3 differ diff --git a/audio/mxblue-travel/config.json b/audio/mxblue-travel/config.json new file mode 100644 index 0000000..b93c5ec --- /dev/null +++ b/audio/mxblue-travel/config.json @@ -0,0 +1,16 @@ +{ + "id": "custom-sound-pack-1720300926821", + "name": "MX Blue - Full Travel", + "key_define_type": "multi", + "sound": "press/GENERIC_R{0-4}.mp3", + "soundup": "release/GENERIC.mp3", + "defines": { + "14": "press/BACKSPACE.mp3", + "14-up": "release/BACKSPACE.mp3", + "28": "press/ENTER.mp3", + "28-up": "release/ENTER.mp3", + "57": "press/SPACE.mp3", + "57-up": "release/SPACE.mp3" + }, + "version": 2 +} \ No newline at end of file diff --git a/audio/mxblue-travel/press/GENERIC_R0.mp3 b/audio/mxblue-travel/press/GENERIC_R0.mp3 new file mode 100644 index 0000000..c9bc9a0 Binary files /dev/null and b/audio/mxblue-travel/press/GENERIC_R0.mp3 differ diff --git a/audio/mxblue-travel/press/GENERIC_R1.mp3 b/audio/mxblue-travel/press/GENERIC_R1.mp3 new file mode 100644 index 0000000..9de4744 Binary files /dev/null and b/audio/mxblue-travel/press/GENERIC_R1.mp3 differ diff --git a/audio/mxblue-travel/press/GENERIC_R2.mp3 b/audio/mxblue-travel/press/GENERIC_R2.mp3 new file mode 100644 index 0000000..81b1b62 Binary files /dev/null and b/audio/mxblue-travel/press/GENERIC_R2.mp3 differ diff --git a/audio/mxblue-travel/press/GENERIC_R3.mp3 b/audio/mxblue-travel/press/GENERIC_R3.mp3 new file mode 100644 index 0000000..c47362b Binary files /dev/null and b/audio/mxblue-travel/press/GENERIC_R3.mp3 differ diff --git a/audio/mxblue-travel/press/GENERIC_R4.mp3 b/audio/mxblue-travel/press/GENERIC_R4.mp3 new file mode 100644 index 0000000..2d41a4d Binary files /dev/null and b/audio/mxblue-travel/press/GENERIC_R4.mp3 differ diff --git a/audio/mxblue-travel/release/GENERIC.mp3 b/audio/mxblue-travel/release/GENERIC.mp3 new file mode 100644 index 0000000..edd0abb Binary files /dev/null and b/audio/mxblue-travel/release/GENERIC.mp3 differ diff --git a/audio/mxbrown-travel/config.json b/audio/mxbrown-travel/config.json new file mode 100644 index 0000000..155bcde --- /dev/null +++ b/audio/mxbrown-travel/config.json @@ -0,0 +1,16 @@ +{ + "id": "custom-sound-pack-1720300926821", + "name": "MX Brown - Full Travel", + "key_define_type": "multi", + "sound": "press/GENERIC_R{0-4}.mp3", + "soundup": "release/GENERIC.mp3", + "defines": { + "14": "press/BACKSPACE.mp3", + "14-up": "release/BACKSPACE.mp3", + "28": "press/ENTER.mp3", + "28-up": "release/ENTER.mp3", + "57": "press/SPACE.mp3", + "57-up": "release/SPACE.mp3" + }, + "version": 2 +} \ No newline at end of file diff --git a/audio/mxbrown-travel/press/BACKSPACE.mp3 b/audio/mxbrown-travel/press/BACKSPACE.mp3 new file mode 100644 index 0000000..0bae8fa Binary files /dev/null and b/audio/mxbrown-travel/press/BACKSPACE.mp3 differ diff --git a/audio/mxbrown-travel/press/ENTER.mp3 b/audio/mxbrown-travel/press/ENTER.mp3 new file mode 100644 index 0000000..6e4f758 Binary files /dev/null and b/audio/mxbrown-travel/press/ENTER.mp3 differ diff --git a/audio/mxbrown-travel/press/GENERIC_R0.mp3 b/audio/mxbrown-travel/press/GENERIC_R0.mp3 new file mode 100644 index 0000000..d525d10 Binary files /dev/null and b/audio/mxbrown-travel/press/GENERIC_R0.mp3 differ diff --git a/audio/mxbrown-travel/press/GENERIC_R1.mp3 b/audio/mxbrown-travel/press/GENERIC_R1.mp3 new file mode 100644 index 0000000..4634843 Binary files /dev/null and b/audio/mxbrown-travel/press/GENERIC_R1.mp3 differ diff --git a/audio/mxbrown-travel/press/GENERIC_R2.mp3 b/audio/mxbrown-travel/press/GENERIC_R2.mp3 new file mode 100644 index 0000000..6205266 Binary files /dev/null and b/audio/mxbrown-travel/press/GENERIC_R2.mp3 differ diff --git a/audio/mxbrown-travel/press/GENERIC_R3.mp3 b/audio/mxbrown-travel/press/GENERIC_R3.mp3 new file mode 100644 index 0000000..3519815 Binary files /dev/null and b/audio/mxbrown-travel/press/GENERIC_R3.mp3 differ diff --git a/audio/mxbrown-travel/press/GENERIC_R4.mp3 b/audio/mxbrown-travel/press/GENERIC_R4.mp3 new file mode 100644 index 0000000..94ffaea Binary files /dev/null and b/audio/mxbrown-travel/press/GENERIC_R4.mp3 differ diff --git a/audio/mxbrown-travel/press/SPACE.mp3 b/audio/mxbrown-travel/press/SPACE.mp3 new file mode 100644 index 0000000..0dabcb0 Binary files /dev/null and b/audio/mxbrown-travel/press/SPACE.mp3 differ diff --git a/audio/mxbrown-travel/release/BACKSPACE.mp3 b/audio/mxbrown-travel/release/BACKSPACE.mp3 new file mode 100644 index 0000000..0bc7d05 Binary files /dev/null and b/audio/mxbrown-travel/release/BACKSPACE.mp3 differ diff --git a/audio/mxbrown-travel/release/ENTER.mp3 b/audio/mxbrown-travel/release/ENTER.mp3 new file mode 100644 index 0000000..9d24928 Binary files /dev/null and b/audio/mxbrown-travel/release/ENTER.mp3 differ diff --git a/audio/mxbrown-travel/release/GENERIC.mp3 b/audio/mxbrown-travel/release/GENERIC.mp3 new file mode 100644 index 0000000..4f8114f Binary files /dev/null and b/audio/mxbrown-travel/release/GENERIC.mp3 differ diff --git a/audio/mxbrown-travel/release/SPACE.mp3 b/audio/mxbrown-travel/release/SPACE.mp3 new file mode 100644 index 0000000..d1a8a8e Binary files /dev/null and b/audio/mxbrown-travel/release/SPACE.mp3 differ diff --git a/audio/nk-cream/[.wav b/audio/nk-cream/[.wav new file mode 100644 index 0000000..30474bb Binary files /dev/null and b/audio/nk-cream/[.wav differ diff --git a/audio/nk-cream/].wav b/audio/nk-cream/].wav new file mode 100644 index 0000000..8cee564 Binary files /dev/null and b/audio/nk-cream/].wav differ diff --git a/audio/nk-cream/a.wav b/audio/nk-cream/a.wav new file mode 100644 index 0000000..23e25b5 Binary files /dev/null and b/audio/nk-cream/a.wav differ diff --git a/audio/nk-cream/b.wav b/audio/nk-cream/b.wav new file mode 100644 index 0000000..04de3fc Binary files /dev/null and b/audio/nk-cream/b.wav differ diff --git a/audio/nk-cream/backspace.wav b/audio/nk-cream/backspace.wav new file mode 100644 index 0000000..1dc56b9 Binary files /dev/null and b/audio/nk-cream/backspace.wav differ diff --git a/audio/nk-cream/c.wav b/audio/nk-cream/c.wav new file mode 100644 index 0000000..5f0bb3d Binary files /dev/null and b/audio/nk-cream/c.wav differ diff --git a/audio/nk-cream/caps lock.wav b/audio/nk-cream/caps lock.wav new file mode 100644 index 0000000..9f46f1e Binary files /dev/null and b/audio/nk-cream/caps lock.wav differ diff --git a/audio/nk-cream/config.json b/audio/nk-cream/config.json new file mode 100644 index 0000000..a8eef3b --- /dev/null +++ b/audio/nk-cream/config.json @@ -0,0 +1,127 @@ +{ + "id": "custom-sound-pack-1599402588730", + "name": "NK Cream (original by Ryan)", + "key_define_type": "multi", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": "q.wav", + "2": "w.wav", + "3": "e.wav", + "4": "e.wav", + "5": "r.wav", + "6": "t.wav", + "7": "y.wav", + "8": "u.wav", + "9": "i.wav", + "10": "o.wav", + "11": "p.wav", + "12": "[.wav", + "13": "].wav", + "14": "backspace.wav", + "15": "tab.wav", + "16": "q.wav", + "17": "w.wav", + "18": "e.wav", + "19": "r.wav", + "20": "t.wav", + "21": "y.wav", + "22": "u.wav", + "23": "i.wav", + "24": "o.wav", + "25": "p.wav", + "26": "[.wav", + "27": "].wav", + "28": "enter.wav", + "29": "tab.wav", + "30": "a.wav", + "31": "s.wav", + "32": "d.wav", + "33": "f.wav", + "34": "g.wav", + "35": "h.wav", + "36": "j.wav", + "37": "k.wav", + "38": "l.wav", + "39": "[.wav", + "40": "].wav", + "41": "q.wav", + "42": "shift.wav", + "43": "backspace.wav", + "44": "z.wav", + "45": "x.wav", + "46": "c.wav", + "47": "v.wav", + "48": "b.wav", + "49": "n.wav", + "50": "m.wav", + "51": "l.wav", + "52": "[.wav", + "53": "].wav", + "54": "shift.wav", + "55": "o.wav", + "56": "e.wav", + "57": "space.wav", + "58": "caps lock.wav", + "59": "w.wav", + "60": "e.wav", + "61": "e.wav", + "62": "r.wav", + "63": "t.wav", + "64": "y.wav", + "65": "u.wav", + "66": "i.wav", + "67": "o.wav", + "68": "p.wav", + "69": "u.wav", + "70": "i.wav", + "71": "y.wav", + "72": "u.wav", + "73": "i.wav", + "74": "p.wav", + "75": "h.wav", + "76": "j.wav", + "77": "k.wav", + "78": "enter.wav", + "79": "b.wav", + "80": "n.wav", + "81": "m.wav", + "82": "shift.wav", + "83": "[.wav", + "87": "].wav", + "88": "].wav", + "91": null, + "92": null, + "93": null, + "3597": null, + "3612": "shift.wav", + "3613": "backspace.wav", + "3637": "i.wav", + "3639": "u.wav", + "3640": "p.wav", + "3653": "o.wav", + "3655": "h.wav", + "3657": "k.wav", + "3663": "n.wav", + "3665": "m.wav", + "3666": "h.wav", + "3667": "b.wav", + "3675": "q.wav", + "3676": "[.wav", + "3677": "].wav", + "57416": "g.wav", + "57419": "c.wav", + "57421": "b.wav", + "57424": "v.wav", + "60999": "h.wav", + "61000": "g.wav", + "61001": "k.wav", + "61003": "c.wav", + "61005": "b.wav", + "61007": "n.wav", + "61008": "v.wav", + "61009": "m.wav", + "61010": "h.wav", + "61011": "b.wav" + } +} diff --git a/audio/nk-cream/d.wav b/audio/nk-cream/d.wav new file mode 100644 index 0000000..372e2c4 Binary files /dev/null and b/audio/nk-cream/d.wav differ diff --git a/audio/nk-cream/e.wav b/audio/nk-cream/e.wav new file mode 100644 index 0000000..0ad8fb8 Binary files /dev/null and b/audio/nk-cream/e.wav differ diff --git a/audio/nk-cream/enter.wav b/audio/nk-cream/enter.wav new file mode 100644 index 0000000..717e2cb Binary files /dev/null and b/audio/nk-cream/enter.wav differ diff --git a/audio/nk-cream/f.wav b/audio/nk-cream/f.wav new file mode 100644 index 0000000..7ccf61e Binary files /dev/null and b/audio/nk-cream/f.wav differ diff --git a/audio/nk-cream/g.wav b/audio/nk-cream/g.wav new file mode 100644 index 0000000..4e2a78f Binary files /dev/null and b/audio/nk-cream/g.wav differ diff --git a/audio/nk-cream/h.wav b/audio/nk-cream/h.wav new file mode 100644 index 0000000..b9fdc30 Binary files /dev/null and b/audio/nk-cream/h.wav differ diff --git a/audio/nk-cream/i.wav b/audio/nk-cream/i.wav new file mode 100644 index 0000000..be7f392 Binary files /dev/null and b/audio/nk-cream/i.wav differ diff --git a/audio/nk-cream/j.wav b/audio/nk-cream/j.wav new file mode 100644 index 0000000..50cf399 Binary files /dev/null and b/audio/nk-cream/j.wav differ diff --git a/audio/nk-cream/k.wav b/audio/nk-cream/k.wav new file mode 100644 index 0000000..04f2229 Binary files /dev/null and b/audio/nk-cream/k.wav differ diff --git a/audio/nk-cream/l.wav b/audio/nk-cream/l.wav new file mode 100644 index 0000000..6d4b876 Binary files /dev/null and b/audio/nk-cream/l.wav differ diff --git a/audio/nk-cream/m.wav b/audio/nk-cream/m.wav new file mode 100644 index 0000000..1624865 Binary files /dev/null and b/audio/nk-cream/m.wav differ diff --git a/audio/nk-cream/n.wav b/audio/nk-cream/n.wav new file mode 100644 index 0000000..a02f066 Binary files /dev/null and b/audio/nk-cream/n.wav differ diff --git a/audio/nk-cream/o.wav b/audio/nk-cream/o.wav new file mode 100644 index 0000000..30474bb Binary files /dev/null and b/audio/nk-cream/o.wav differ diff --git a/audio/nk-cream/p.wav b/audio/nk-cream/p.wav new file mode 100644 index 0000000..8cee564 Binary files /dev/null and b/audio/nk-cream/p.wav differ diff --git a/audio/nk-cream/q.wav b/audio/nk-cream/q.wav new file mode 100644 index 0000000..7032a46 Binary files /dev/null and b/audio/nk-cream/q.wav differ diff --git a/audio/nk-cream/r.wav b/audio/nk-cream/r.wav new file mode 100644 index 0000000..e172224 Binary files /dev/null and b/audio/nk-cream/r.wav differ diff --git a/audio/nk-cream/s.wav b/audio/nk-cream/s.wav new file mode 100644 index 0000000..badb009 Binary files /dev/null and b/audio/nk-cream/s.wav differ diff --git a/audio/nk-cream/shift.wav b/audio/nk-cream/shift.wav new file mode 100644 index 0000000..717e2cb Binary files /dev/null and b/audio/nk-cream/shift.wav differ diff --git a/audio/nk-cream/space.wav b/audio/nk-cream/space.wav new file mode 100644 index 0000000..b1b671f Binary files /dev/null and b/audio/nk-cream/space.wav differ diff --git a/audio/nk-cream/t.wav b/audio/nk-cream/t.wav new file mode 100644 index 0000000..018b90c Binary files /dev/null and b/audio/nk-cream/t.wav differ diff --git a/audio/nk-cream/tab.wav b/audio/nk-cream/tab.wav new file mode 100644 index 0000000..9f46f1e Binary files /dev/null and b/audio/nk-cream/tab.wav differ diff --git a/audio/nk-cream/u.wav b/audio/nk-cream/u.wav new file mode 100644 index 0000000..563754a Binary files /dev/null and b/audio/nk-cream/u.wav differ diff --git a/audio/nk-cream/v.wav b/audio/nk-cream/v.wav new file mode 100644 index 0000000..f24e97b Binary files /dev/null and b/audio/nk-cream/v.wav differ diff --git a/audio/nk-cream/w.wav b/audio/nk-cream/w.wav new file mode 100644 index 0000000..61980f4 Binary files /dev/null and b/audio/nk-cream/w.wav differ diff --git a/audio/nk-cream/x.wav b/audio/nk-cream/x.wav new file mode 100644 index 0000000..f15c6f6 Binary files /dev/null and b/audio/nk-cream/x.wav differ diff --git a/audio/nk-cream/y.wav b/audio/nk-cream/y.wav new file mode 100644 index 0000000..4a24977 Binary files /dev/null and b/audio/nk-cream/y.wav differ diff --git a/audio/nk-cream/z.wav b/audio/nk-cream/z.wav new file mode 100644 index 0000000..400a534 Binary files /dev/null and b/audio/nk-cream/z.wav differ diff --git a/audio/topre-purple-hybrid-pbt/config.json b/audio/topre-purple-hybrid-pbt/config.json new file mode 100644 index 0000000..a5a517f --- /dev/null +++ b/audio/topre-purple-hybrid-pbt/config.json @@ -0,0 +1,465 @@ +{ + "id": "custom-sound-pack-1582707445334", + "name": "Topre Purple Hybrid - PBT keycaps", + "key_define_type": "single", + "includes_numpad": false, + "sound": "sound.ogg", + "defines": { + "1": [ + 1813, + 130 + ], + "2": [ + 20987, + 180 + ], + "3": [ + 22041, + 183 + ], + "4": [ + 23126, + 194 + ], + "5": [ + 24260, + 191 + ], + "6": [ + 25371, + 185 + ], + "7": [ + 26392, + 189 + ], + "8": [ + 27457, + 180 + ], + "9": [ + 28502, + 175 + ], + "10": [ + 29566, + 192 + ], + "11": [ + 30619, + 200 + ], + "12": [ + 31656, + 191 + ], + "13": [ + 31712, + 191 + ], + "14": [ + 33746, + 190 + ], + "15": [ + 37933, + 184 + ], + "16": [ + 39000, + 180 + ], + "17": [ + 39991, + 188 + ], + "18": [ + 40955, + 200 + ], + "19": [ + 41924, + 190 + ], + "20": [ + 42918, + 192 + ], + "21": [ + 43909, + 180 + ], + "22": [ + 44822, + 185 + ], + "23": [ + 45779, + 194 + ], + "24": [ + 46763, + 175 + ], + "25": [ + 47787, + 200 + ], + "26": [ + 48805, + 208 + ], + "27": [ + 49764, + 171 + ], + "28": [ + 68501, + 174 + ], + "29": [ + 84014, + 174 + ], + "30": [ + 56440, + 177 + ], + "31": [ + 57571, + 198 + ], + "32": [ + 58641, + 182 + ], + "33": [ + 59729, + 182 + ], + "34": [ + 60765, + 183 + ], + "35": [ + 61898, + 171 + ], + "36": [ + 63008, + 180 + ], + "37": [ + 64156, + 168 + ], + "38": [ + 65199, + 171 + ], + "39": [ + 66281, + 167 + ], + "40": [ + 67418, + 175 + ], + "41": [ + 19950, + 190 + ], + "42": [ + 69592, + 186 + ], + "43": [ + 50707, + 183 + ], + "44": [ + 70895, + 174 + ], + "45": [ + 72019, + 184 + ], + "46": [ + 73119, + 192 + ], + "47": [ + 74276, + 198 + ], + "48": [ + 75328, + 193 + ], + "49": [ + 76458, + 170 + ], + "50": [ + 77514, + 190 + ], + "51": [ + 78570, + 180 + ], + "52": [ + 79601, + 175 + ], + "53": [ + 80675, + 160 + ], + "54": [ + 81734, + 176 + ], + "55": [ + 18833, + 200 + ], + "56": [ + 86211, + 187 + ], + "57": [ + 87213, + 181 + ], + "58": [ + 55235, + 205 + ], + "59": [ + 3076, + 149 + ], + "60": [ + 4300, + 166 + ], + "61": [ + 5415, + 168 + ], + "62": [ + 6581, + 162 + ], + "63": [ + 7724, + 184 + ], + "64": [ + 8860, + 197 + ], + "65": [ + 9972, + 195 + ], + "66": [ + 1119, + 182 + ], + "67": [ + 12242, + 178 + ], + "68": [ + 13401, + 194 + ], + "69": [ + 16619, + 166 + ], + "70": [ + 17743, + 200 + ], + "71": [ + 34738, + 166 + ], + "72": [ + 35728, + 186 + ], + "73": [ + 36825, + 175 + ], + "74": [ + 31656, + 191 + ], + "75": [ + 51695, + 200 + ], + "76": [ + 52666, + 163 + ], + "77": [ + 53744, + 192 + ], + "78": [ + 33746, + 190 + ], + "79": [ + 92565, + 173 + ], + "80": [ + 93711, + 174 + ], + "81": [ + 93739, + 195 + ], + "82": [ + 81734, + 176 + ], + "83": [ + 82838, + 211 + ], + "87": [ + 14479, + 189 + ], + "88": [ + 15559, + 187 + ], + "3612": [ + 68501, + 174 + ], + "3613": [ + 91445, + 198 + ], + "3637": [ + 17743, + 200 + ], + "3639": [ + 16619, + 166 + ], + "3640": [ + 88293, + 169 + ], + "3653": [ + 18833, + 200 + ], + "3655": [ + 35728, + 186 + ], + "3657": [ + 36825, + 175 + ], + "3663": [ + 52666, + 163 + ], + "3665": [ + 53744, + 192 + ], + "3666": [ + 34738, + 166 + ], + "3667": [ + 51695, + 200 + ], + "3675": [ + 85179, + 173 + ], + "3676": [ + 89346, + 164 + ], + "3677": [ + 91445, + 198 + ], + "57416": [ + 82838, + 211 + ], + "57419": [ + 92565, + 173 + ], + "57421": [ + 93739, + 195 + ], + "57424": [ + 93711, + 174 + ], + "60999": [ + 35728, + 186 + ], + "61000": [ + 82838, + 211 + ], + "61001": [ + 36825, + 175 + ], + "61003": [ + 92565, + 173 + ], + "61005": [ + 93739, + 195 + ], + "61007": [ + 52666, + 163 + ], + "61008": [ + 93711, + 174 + ], + "61009": [ + 53744, + 192 + ], + "61010": [ + 34738, + 166 + ], + "61011": [ + 51695, + 200 + ] + } +} \ No newline at end of file diff --git a/audio/topre-purple-hybrid-pbt/sound.ogg b/audio/topre-purple-hybrid-pbt/sound.ogg new file mode 100644 index 0000000..543a292 Binary files /dev/null and b/audio/topre-purple-hybrid-pbt/sound.ogg differ diff --git a/audio/turquoise/config.json b/audio/turquoise/config.json new file mode 100644 index 0000000..8d6d8b0 --- /dev/null +++ b/audio/turquoise/config.json @@ -0,0 +1,16 @@ +{ + "id": "custom-sound-pack-1720300926821", + "name": "Turquoise (Full Travel)", + "key_define_type": "multi", + "sound": "press/GENERIC_R{0-4}.mp3", + "soundup": "release/GENERIC.mp3", + "defines": { + "14": "press/BACKSPACE.mp3", + "14-up": "release/BACKSPACE.mp3", + "28": "press/ENTER.mp3", + "28-up": "release/ENTER.mp3", + "57": "press/SPACE.mp3", + "57-up": "release/SPACE.mp3" + }, + "version": 2 +} \ No newline at end of file diff --git a/audio/turquoise/press/BACKSPACE.mp3 b/audio/turquoise/press/BACKSPACE.mp3 new file mode 100644 index 0000000..69c6029 Binary files /dev/null and b/audio/turquoise/press/BACKSPACE.mp3 differ diff --git a/audio/turquoise/press/ENTER.mp3 b/audio/turquoise/press/ENTER.mp3 new file mode 100644 index 0000000..6299435 Binary files /dev/null and b/audio/turquoise/press/ENTER.mp3 differ diff --git a/audio/turquoise/press/GENERIC_R0.mp3 b/audio/turquoise/press/GENERIC_R0.mp3 new file mode 100644 index 0000000..9c4d891 Binary files /dev/null and b/audio/turquoise/press/GENERIC_R0.mp3 differ diff --git a/audio/turquoise/press/GENERIC_R1.mp3 b/audio/turquoise/press/GENERIC_R1.mp3 new file mode 100644 index 0000000..2ce90c3 Binary files /dev/null and b/audio/turquoise/press/GENERIC_R1.mp3 differ diff --git a/audio/turquoise/press/GENERIC_R2.mp3 b/audio/turquoise/press/GENERIC_R2.mp3 new file mode 100644 index 0000000..37ccdb4 Binary files /dev/null and b/audio/turquoise/press/GENERIC_R2.mp3 differ diff --git a/audio/turquoise/press/GENERIC_R3.mp3 b/audio/turquoise/press/GENERIC_R3.mp3 new file mode 100644 index 0000000..a41d3a1 Binary files /dev/null and b/audio/turquoise/press/GENERIC_R3.mp3 differ diff --git a/audio/turquoise/press/GENERIC_R4.mp3 b/audio/turquoise/press/GENERIC_R4.mp3 new file mode 100644 index 0000000..af772ff Binary files /dev/null and b/audio/turquoise/press/GENERIC_R4.mp3 differ diff --git a/audio/turquoise/press/SPACE.mp3 b/audio/turquoise/press/SPACE.mp3 new file mode 100644 index 0000000..4cd97b5 Binary files /dev/null and b/audio/turquoise/press/SPACE.mp3 differ diff --git a/audio/turquoise/release/BACKSPACE.mp3 b/audio/turquoise/release/BACKSPACE.mp3 new file mode 100644 index 0000000..e05b35f Binary files /dev/null and b/audio/turquoise/release/BACKSPACE.mp3 differ diff --git a/audio/turquoise/release/ENTER.mp3 b/audio/turquoise/release/ENTER.mp3 new file mode 100644 index 0000000..105035e Binary files /dev/null and b/audio/turquoise/release/ENTER.mp3 differ diff --git a/audio/turquoise/release/GENERIC.mp3 b/audio/turquoise/release/GENERIC.mp3 new file mode 100644 index 0000000..7df554b Binary files /dev/null and b/audio/turquoise/release/GENERIC.mp3 differ diff --git a/audio/turquoise/release/SPACE.mp3 b/audio/turquoise/release/SPACE.mp3 new file mode 100644 index 0000000..10c5b6c Binary files /dev/null and b/audio/turquoise/release/SPACE.mp3 differ diff --git a/config.h b/config.h new file mode 100644 index 0000000..1347bde --- /dev/null +++ b/config.h @@ -0,0 +1,20 @@ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ + +#define PROJECT_VERSION "1.1.0" +#define GETTEXT_PACKAGE "keyvibe" +#define PKEXEC_PATH "/usr/bin/pkexec" + +// Prefix macro should be defined by compiler flags, fallback to /usr +#ifndef PACKAGE_PREFIX +#define PACKAGE_PREFIX "/usr" +#endif + +#define PACKAGE_BINDIR PACKAGE_PREFIX "/bin" +#define PACKAGE_LOCALEDIR PACKAGE_PREFIX "/share/locale" + +// KeyVibe specific paths relative to prefix +#define KeyVibe_DATA_DIR PACKAGE_PREFIX "/share/keyvibe" +#define KeyVibe_BIN_DIR PACKAGE_PREFIX "/bin" + +#endif diff --git a/get_key_presses.c b/get_key_presses.c new file mode 100644 index 0000000..ee89d52 --- /dev/null +++ b/get_key_presses.c @@ -0,0 +1,262 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "config.h" + +#define MAX_BUFFER_LENGTH 512 + +enum error_code { + NO_ERROR, + UDEV_FAILED, + LIBINPUT_FAILED, + SEAT_FAILED, + PERMISSION_FAILED +}; + +struct input_handler_data { + struct udev *udev; + struct libinput *libinput; +}; + +static void *handle_input(void *user_data) +{ + struct input_handler_data *input_handler_data = user_data; + + char line[MAX_BUFFER_LENGTH]; + while (fgets(line, MAX_BUFFER_LENGTH, stdin) != NULL) { + if (strcmp(line, "stop\n") == 0) { + libinput_unref(input_handler_data->libinput); + udev_unref(input_handler_data->udev); + exit(EXIT_SUCCESS); + } + } + + return NULL; +} + +static int open_restricted(const char *path, int flags, void *user_data) +{ + (void)user_data; + int fd = open(path, flags); + if (fd < 0) + fprintf(stderr, "Failed to open %s because of %s.\n", path, + strerror(errno)); + return fd < 0 ? -errno : fd; +} + +static void close_restricted(int fd, void *user_data) +{ + (void)user_data; + close(fd); +} + +static const struct libinput_interface interface = { + .open_restricted = open_restricted, + .close_restricted = close_restricted, +}; + +static int print_key_event(struct libinput_event *event) +{ + struct libinput_event_keyboard *keyboard = + libinput_event_get_keyboard_event(event); + + enum libinput_event_type event_type = libinput_event_get_type(event); + uint32_t time_stamp = libinput_event_keyboard_get_time(keyboard); + uint32_t key_code = libinput_event_keyboard_get_key(keyboard); + const char *key_name = libevdev_event_code_get_name(EV_KEY, key_code); + key_name = key_name ? key_name : "null"; + enum libinput_key_state state_code = + libinput_event_keyboard_get_key_state(keyboard); + const char *state_name = state_code == LIBINPUT_KEY_STATE_PRESSED ? + "PRESSED" : + "RELEASED"; + + return printf("{" + "\"event_name\": \"KEYBOARD_KEY\", " + "\"event_type\": %d, " + "\"time_stamp\": %d, " + "\"key_name\": \"%s\", " + "\"key_code\": %d, " + "\"state_name\": \"%s\", " + "\"state_code\": %d" + "}\n", + event_type, time_stamp, key_name, key_code, state_name, + state_code); +} + +static int print_button_event(struct libinput_event *event) +{ + struct libinput_event_pointer *pointer = + libinput_event_get_pointer_event(event); + + enum libinput_event_type event_type = libinput_event_get_type(event); + uint32_t time_stamp = libinput_event_pointer_get_time(pointer); + uint32_t button_code = libinput_event_pointer_get_button(pointer); + const char *button_name = + libevdev_event_code_get_name(EV_KEY, button_code); + enum libinput_button_state state_code = + libinput_event_pointer_get_button_state(pointer); + const char *state_name = state_code == LIBINPUT_BUTTON_STATE_PRESSED ? + "PRESSED" : + "RELEASED"; + return printf("{" + "\"event_name\": \"POINTER_BUTTON\", " + "\"event_type\": %d, " + "\"time_stamp\": %d, " + "\"key_name\": \"%s\", " + "\"key_code\": %d, " + "\"state_name\": \"%s\", " + "\"state_code\": %d" + "}\n", + event_type, time_stamp, button_name, button_code, + state_name, state_code); +} + +static int handle_events(struct libinput *libinput) +{ + int result = -1; + struct libinput_event *event; + + if (libinput_dispatch(libinput) < 0) + return result; + + // Please keep printing a line per json. + while ((event = libinput_get_event(libinput)) != NULL) { + switch (libinput_event_get_type(event)) { + // This program only handle key event. + case LIBINPUT_EVENT_KEYBOARD_KEY: + print_key_event(event); + break; + // Sorry, mouse button is also a key. + case LIBINPUT_EVENT_POINTER_BUTTON: + print_button_event(event); + break; + default: + break; + } + // Do a `fflush(stdout)` here, so when we write to pipes, + // the other one can always get a latest result. + // If we don't have `fflush(stdout)` here, pipe will save + // some lines in buffer and pass them together. + fflush(stdout); + libinput_event_destroy(event); + result = 0; + } + + return result; +} + +static int run_mainloop(struct libinput *libinput) +{ + struct pollfd fd; + fd.fd = libinput_get_fd(libinput); + fd.events = POLLIN; + fd.revents = 0; + + if (handle_events(libinput) != 0) { + fprintf(stderr, + "Expected device added events on startup but " + "got none. Maybe you don't have the right permissions?" + "\n"); + return -1; + } + while (poll(&fd, 1, -1) > -1) + handle_events(libinput); + return 0; +} + +void print_help(char *program_name) +{ + printf("The backend of Show Me The Key.\n"); + printf("Version " PROJECT_VERSION ".\n"); + printf("Usage: %s [OPTION…]\n", program_name); + printf("Options:\n"); + printf("\t-h, --help\tDisplay help then exit.\n"); + printf("\t-v, --version\tDisplay version then exit.\n"); + printf("Warning: This is the backend and is not designed to run " + "by users. You should run the frontend of Show Me The Key, " + "and the frontend will run this.\n"); +} + +int main(int argc, char *argv[]) +{ + const struct option long_options[] = { { "version", no_argument, 0, + 'v' }, + { "help", no_argument, 0, 'h' }, + { NULL, 0, NULL, 0 } }; + + int option_index = 0; + int opt = 0; + while ((opt = getopt_long(argc, argv, "vh", long_options, + &option_index)) != -1) { + switch (opt) { + case 0: + // We don't use this. + break; + case 'v': + printf(PROJECT_VERSION "\n"); + return 0; + case 'h': + print_help(argv[0]); + return 0; + case '?': + // getopt_long already printed an error message. + break; + default: + fprintf(stderr, "%s: Invalid option `-%c`.\n", argv[0], + opt); + break; + } + } + + struct udev *udev = udev_new(); + if (udev == NULL) { + fprintf(stderr, "Failed to initialize udev.\n"); + return UDEV_FAILED; + } + + struct libinput *libinput = + libinput_udev_create_context(&interface, NULL, udev); + if (!libinput) { + fprintf(stderr, "Failed to initialize libinput from udev.\n"); + return LIBINPUT_FAILED; + } + + // TODO: Support custom seat. + if (libinput_udev_assign_seat(libinput, "seat0") != 0) { + fprintf(stderr, "Failed to set seat.\n"); + libinput_unref(libinput); + udev_unref(udev); + return SEAT_FAILED; + } + + // Typically this will be run with pkexec as a subprocess, + // and the parent cannot kill it because it is privileged, + // so we use another thread to see if it gets "stop\n" from stdin, + // it will exit by itself. + pthread_t input_handler; + struct input_handler_data input_handler_data = { udev, libinput }; + pthread_create(&input_handler, NULL, handle_input, &input_handler_data); + + if (run_mainloop(libinput) < 0) + return PERMISSION_FAILED; + + libinput_unref(libinput); + udev_unref(udev); + + return NO_ERROR; +} diff --git a/keyboard_sound_player.c b/keyboard_sound_player.c new file mode 100644 index 0000000..b3fcbd3 --- /dev/null +++ b/keyboard_sound_player.c @@ -0,0 +1,642 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // For dirname + +#define MAX_LINE_LENGTH 1024 +#define MAX_CONCURRENT_SOUNDS 10 + +typedef struct { + int start_ms; + int duration_ms; +} SoundMapping; + +typedef struct { + char press_file[256]; // used in multi mode + char release_file[256]; // used in multi mode + char generic_press_files[5][256]; // max 5 files GENERIC_R0..R4 + int num_generic_press_files; + + char sound_file[256]; // used in single mode + SoundMapping key_mappings[256]; // only for 'single' mode + + struct { + char *press; + char *release; + } multi_key_mappings[256]; + + int is_multi; + SF_INFO sf_info; +} SoundPack; + +typedef struct { + int key_code; + SoundPack *sound_pack; + int thread_id; + int is_pressed; +} PlaybackData; + +// Global sound pack +SoundPack g_sound_pack = {0}; +float g_volume = 1.0f; +int g_verbose = 0; + +// Thread pool for sound playback +pthread_t sound_threads[MAX_CONCURRENT_SOUNDS]; +volatile int thread_active[MAX_CONCURRENT_SOUNDS] = {0}; +pthread_mutex_t thread_mutex = PTHREAD_MUTEX_INITIALIZER; + +// Function to construct a full path +static void get_full_path(char *buffer, size_t buffer_size, const char *base_dir, const char *filename) { + if (filename == NULL || base_dir == NULL) { + buffer[0] = '\0'; + return; + } + // Check if filename is already an absolute path + if (filename[0] == '/') { + strncpy(buffer, filename, buffer_size - 1); + buffer[buffer_size - 1] = '\0'; + } else { + snprintf(buffer, buffer_size, "%s/%s", base_dir, filename); + } +} + + +int load_sound_config(const char *config_path) { + FILE *file = fopen(config_path, "r"); + if (!file) { + fprintf(stderr, "Error: Cannot open config file: %s\n", config_path); + perror("fopen"); + return -1; + } + + // Extract the directory of the config file + char config_path_copy[MAX_LINE_LENGTH]; // Use a copy because dirname can modify its argument + strncpy(config_path_copy, config_path, sizeof(config_path_copy) - 1); + config_path_copy[sizeof(config_path_copy) - 1] = '\0'; + char *config_dir = dirname(config_path_copy); + + fseek(file, 0, SEEK_END); + long size = ftell(file); + rewind(file); + + char *json_string = malloc(size + 1); + if (!json_string) { + fclose(file); + fprintf(stderr, "Error: Memory allocation failed\n"); + return -1; + } + + fread(json_string, 1, size, file); + json_string[size] = '\0'; + fclose(file); + + json_object *root = json_tokener_parse(json_string); + free(json_string); + if (!root) { + fprintf(stderr, "Error: Invalid JSON in config file\n"); + return -1; + } + + const char *key_type = "single"; + json_object *obj; + if (json_object_object_get_ex(root, "key_define_type", &obj)) + key_type = json_object_get_string(obj); + + g_sound_pack.is_multi = strcmp(key_type, "multi") == 0; + printf("Config loaded: Using %s mode\n", g_sound_pack.is_multi ? "multi" : "single"); + + if (g_sound_pack.is_multi) { + // Reset counter + g_sound_pack.num_generic_press_files = 0; + + if (json_object_object_get_ex(root, "sound", &obj)) { + const char *pattern = json_object_get_string(obj); + printf("Sound pattern: %s\n", pattern); + + // Check if pattern contains format specifier + if (strstr(pattern, "%d") || strstr(pattern, "{")) { + // Handle patterns like "GENERIC_R%d.mp3" or "GENERIC_R{0-4}.mp3" + for (int i = 0; i <= 4; i++) { + char temp_filename[256]; + if (strstr(pattern, "{")) { + // Replace {0-4} with actual number + char temp_pattern[256]; + strncpy(temp_pattern, pattern, sizeof(temp_pattern) - 1); + temp_pattern[sizeof(temp_pattern) - 1] = '\0'; + + // Simple replacement of {0-4} with %d + char *brace_start = strstr(temp_pattern, "{"); + char *brace_end = strstr(temp_pattern, "}"); + if (brace_start && brace_end) { + *brace_start = '%'; + *(brace_start + 1) = 'd'; + memmove(brace_start + 2, brace_end + 1, strlen(brace_end + 1) + 1); + } + snprintf(temp_filename, sizeof(temp_filename), temp_pattern, i); + } else { + snprintf(temp_filename, sizeof(temp_filename), pattern, i); + } + + // Construct the full path using the config directory + get_full_path(g_sound_pack.generic_press_files[i], sizeof(g_sound_pack.generic_press_files[i]), config_dir, temp_filename); + + // Check if file exists before adding to count + if (access(g_sound_pack.generic_press_files[i], R_OK) == 0) { + g_sound_pack.num_generic_press_files = i + 1; // Keep track of highest valid index + 1 + // printf("Found generic sound file: %s\n", g_sound_pack.generic_press_files[i]); + } else { + printf("Generic sound file not found: %s\n", g_sound_pack.generic_press_files[i]); + break; // Stop at first missing file + } + } + } else { + // Direct filename, no pattern + get_full_path(g_sound_pack.generic_press_files[0], sizeof(g_sound_pack.generic_press_files[0]), config_dir, pattern); + if (access(g_sound_pack.generic_press_files[0], R_OK) == 0) { + g_sound_pack.num_generic_press_files = 1; + printf("Found single generic sound file: %s\n", g_sound_pack.generic_press_files[0]); + } + } + + printf("Total generic press sound files: %d\n", g_sound_pack.num_generic_press_files); + } + + if (json_object_object_get_ex(root, "soundup", &obj)) { + char temp_release_file[256]; + strncpy(temp_release_file, json_object_get_string(obj), sizeof(temp_release_file) - 1); + temp_release_file[sizeof(temp_release_file) - 1] = '\0'; + get_full_path(g_sound_pack.release_file, sizeof(g_sound_pack.release_file), config_dir, temp_release_file); + printf("Release sound file: %s\n", g_sound_pack.release_file); + } + + if (json_object_object_get_ex(root, "defines", &obj)) { + // printf("Processing key definitions...\n"); + json_object_object_foreach(obj, key, val) { + int key_code; + int is_release = 0; + char *dash = strstr(key, "-up"); + if (dash) { + char key_copy[16]; + strncpy(key_copy, key, dash - key); + key_copy[dash - key] = '\0'; + key_code = atoi(key_copy); + is_release = 1; + } else { + key_code = atoi(key); + } + + if (key_code >= 0 && key_code < 256) { + const char *filename_relative = json_object_get_string(val); + char full_filename[MAX_LINE_LENGTH]; + get_full_path(full_filename, sizeof(full_filename), config_dir, filename_relative); + // printf("Key %d (%s): %s (full path: %s)\n", key_code, is_release ? "release" : "press", filename_relative, full_filename); + + if (is_release) { + if (g_sound_pack.multi_key_mappings[key_code].release) { + free(g_sound_pack.multi_key_mappings[key_code].release); + } + g_sound_pack.multi_key_mappings[key_code].release = strdup(full_filename); + } else { + if (g_sound_pack.multi_key_mappings[key_code].press) { + free(g_sound_pack.multi_key_mappings[key_code].press); + } + g_sound_pack.multi_key_mappings[key_code].press = strdup(full_filename); + } + } + } + } + } else { // Single mode + if (json_object_object_get_ex(root, "sound", &obj)) { + char temp_sound_file[256]; + strncpy(temp_sound_file, json_object_get_string(obj), sizeof(temp_sound_file) - 1); + temp_sound_file[sizeof(temp_sound_file) - 1] = '\0'; + get_full_path(g_sound_pack.sound_file, sizeof(g_sound_pack.sound_file), config_dir, temp_sound_file); + printf("Single mode sound file: %s\n", g_sound_pack.sound_file); + } + + if (json_object_object_get_ex(root, "defines", &obj)) { + json_object_object_foreach(obj, key, val) { + int key_code = atoi(key); + if (key_code >= 0 && key_code < 256 && + json_object_is_type(val, json_type_array) && + json_object_array_length(val) >= 2) { + g_sound_pack.key_mappings[key_code].start_ms = json_object_get_int(json_object_array_get_idx(val, 0)); + g_sound_pack.key_mappings[key_code].duration_ms = json_object_get_int(json_object_array_get_idx(val, 1)); + } + } + } + } + + json_object_put(root); + return 0; +} + +int init_audio() { + // For multi mode, we don't need to check a single sound file + if (g_sound_pack.is_multi) { + // printf("Multi mode: Audio will be initialized per sound file\n"); + return 0; + } + + // For single mode, check the main sound file + if (strlen(g_sound_pack.sound_file) == 0) { + fprintf(stderr, "Error: No sound file specified in config\n"); + return -1; + } + + if (access(g_sound_pack.sound_file, R_OK) != 0) { + fprintf(stderr, "Sound file not accessible: %s\n", g_sound_pack.sound_file); + perror("access"); + return -1; + } + + // Test open sound file to get info + SNDFILE *test_sf = sf_open(g_sound_pack.sound_file, SFM_READ, &g_sound_pack.sf_info); + if (!test_sf) { + fprintf(stderr, "Could not open sound file: %s\n", g_sound_pack.sound_file); + fprintf(stderr, "libsndfile error: %s\n", sf_strerror(NULL)); + return -1; + } + sf_close(test_sf); + + printf("Sound file info: %ld frames, %d channels, %d Hz\n", + g_sound_pack.sf_info.frames, g_sound_pack.sf_info.channels, g_sound_pack.sf_info.samplerate); + + return 0; +} + +void* play_sound_thread(void* arg) { + PlaybackData *data = (PlaybackData*)arg; + int key_code = data->key_code; + int thread_id = data->thread_id; + int is_pressed = data->is_pressed; + + const char *file_to_play = NULL; + + if (g_verbose) { + printf("Thread %d: Playing sound for key %d (%s)\n", + thread_id, key_code, is_pressed ? "press" : "release"); + } + + if (g_sound_pack.is_multi) { + // First try exact match + if (is_pressed && g_sound_pack.multi_key_mappings[key_code].press) { + file_to_play = g_sound_pack.multi_key_mappings[key_code].press; + } else if (!is_pressed && g_sound_pack.multi_key_mappings[key_code].release) { + file_to_play = g_sound_pack.multi_key_mappings[key_code].release; + } else if (is_pressed && g_sound_pack.num_generic_press_files > 0) { + // Fallback: random generic press + int idx = rand() % g_sound_pack.num_generic_press_files; + file_to_play = g_sound_pack.generic_press_files[idx]; + } else if (!is_pressed && strlen(g_sound_pack.release_file) > 0) { + file_to_play = g_sound_pack.release_file; + } + + if (!file_to_play) { + if (g_verbose) { + printf("Thread %d: No sound file found for key %d (%s)\n", + thread_id, key_code, is_pressed ? "press" : "release"); + } + goto exit_cleanup; + } + + if (g_verbose) { + printf("Thread %d: Using sound file: %s\n", thread_id, file_to_play); + } + + SF_INFO sf_info = {0}; + SNDFILE *sf = sf_open(file_to_play, SFM_READ, &sf_info); + if (!sf) { + fprintf(stderr, "Could not open sound file: %s (Error: %s)\n", + file_to_play, sf_strerror(NULL)); + goto exit_cleanup; + } + + pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = sf_info.samplerate, + .channels = sf_info.channels + }; + + int pa_error; + pa_simple *pa_handle = pa_simple_new(NULL, "KeyboardSounds", PA_STREAM_PLAYBACK, + NULL, "playback", &ss, NULL, NULL, &pa_error); + if (!pa_handle) { + fprintf(stderr, "Could not initialize PulseAudio: %s\n", pa_strerror(pa_error)); + sf_close(sf); + goto exit_cleanup; + } + + int frames = 2048; + short *buffer = malloc(frames * sf_info.channels * sizeof(short)); + if (!buffer) { + pa_simple_free(pa_handle); + sf_close(sf); + goto exit_cleanup; + } + + sf_count_t read; + while ((read = sf_readf_short(sf, buffer, frames)) > 0) { + for (sf_count_t i = 0; i < read * sf_info.channels; i++) { + buffer[i] = (short)(buffer[i] * g_volume); + } + + int pa_write_error; + if (pa_simple_write(pa_handle, buffer, read * sf_info.channels * sizeof(short), &pa_write_error) < 0) { + fprintf(stderr, "PulseAudio write error: %s\n", pa_strerror(pa_write_error)); + break; + } + } + + int pa_drain_error; + pa_simple_drain(pa_handle, &pa_drain_error); + pa_simple_free(pa_handle); + sf_close(sf); + free(buffer); + } else { + if (key_code >= 256 || g_sound_pack.key_mappings[key_code].duration_ms == 0) { + if (g_verbose) { + printf("Thread %d: No mapping for key %d\n", thread_id, key_code); + } + goto exit_cleanup; + } + + SoundMapping *mapping = &g_sound_pack.key_mappings[key_code]; + + SF_INFO sf_info = g_sound_pack.sf_info; + SNDFILE *sf = sf_open(g_sound_pack.sound_file, SFM_READ, &sf_info); + if (!sf) { + fprintf(stderr, "Thread: Could not open sound file\n"); + goto exit_cleanup; + } + + pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = sf_info.samplerate, + .channels = sf_info.channels + }; + + int pa_error; + pa_simple *pa_handle = pa_simple_new(NULL, "KeyboardSounds", PA_STREAM_PLAYBACK, + NULL, "playback", &ss, NULL, NULL, &pa_error); + if (!pa_handle) { + sf_close(sf); + fprintf(stderr, "Thread: Could not initialize PulseAudio: %s\n", pa_strerror(pa_error)); + goto exit_cleanup; + } + + sf_count_t start_frame = (mapping->start_ms * sf_info.samplerate) / 1000; + sf_count_t duration_frames = (mapping->duration_ms * sf_info.samplerate) / 1000; + + sf_seek(sf, start_frame, SEEK_SET); + + short *buffer = malloc(duration_frames * sf_info.channels * sizeof(short)); + if (!buffer) { + pa_simple_free(pa_handle); + sf_close(sf); + goto exit_cleanup; + } + + sf_count_t frames_read = sf_readf_short(sf, buffer, duration_frames); + + for (sf_count_t i = 0; i < frames_read * sf_info.channels; i++) { + buffer[i] = (short)(buffer[i] * g_volume); + } + + int pa_write_error, pa_drain_error; + pa_simple_write(pa_handle, buffer, frames_read * sf_info.channels * sizeof(short), &pa_write_error); + pa_simple_drain(pa_handle, &pa_drain_error); + + free(buffer); + pa_simple_free(pa_handle); + sf_close(sf); + } + +exit_cleanup: + pthread_mutex_lock(&thread_mutex); + thread_active[thread_id] = 0; + pthread_mutex_unlock(&thread_mutex); + free(data); + return NULL; +} + +int find_available_thread_slot() { + pthread_mutex_lock(&thread_mutex); + + // Find available slot + for (int i = 0; i < MAX_CONCURRENT_SOUNDS; i++) { + if (!thread_active[i]) { + pthread_mutex_unlock(&thread_mutex); + return i; + } + } + + pthread_mutex_unlock(&thread_mutex); + return -1; // No available slots +} + +void play_sound_segment(int key_code, int is_pressed) { + // Only play sound on key press in single mode + if (!g_sound_pack.is_multi && !is_pressed) { + if (g_verbose) { + printf("Single mode: Ignoring key release for key %d\n", key_code); + } + return; + } + + int slot = find_available_thread_slot(); + if (slot == -1) { + if (g_verbose) { + printf("Warning: No available thread slots\n"); + } + return; + } + + PlaybackData *data = malloc(sizeof(PlaybackData)); + if (!data) return; + + data->key_code = key_code; + data->sound_pack = &g_sound_pack; + data->thread_id = slot; + data->is_pressed = is_pressed; + + pthread_mutex_lock(&thread_mutex); + thread_active[slot] = 1; + + if (pthread_create(&sound_threads[slot], NULL, play_sound_thread, data) != 0) { + thread_active[slot] = 0; + free(data); + fprintf(stderr, "Failed to create sound thread\n"); + } else { + pthread_detach(sound_threads[slot]); + } + + pthread_mutex_unlock(&thread_mutex); +} + +int parse_keyboard_event(const char *json_line, int *key_code, int *is_pressed) { + // Strip newline if present + char *line_copy = strdup(json_line); + if (!line_copy) return -1; + + char *newline = strchr(line_copy, '\n'); + if (newline) *newline = '\0'; + + if (g_verbose) { + printf("Parsing JSON: %s\n", line_copy); + } + + json_object *root = json_tokener_parse(line_copy); + free(line_copy); + + if (!root) { + fprintf(stderr, "Failed to parse JSON: %s\n", json_line); + return -1; + } + + json_object *key_code_obj, *state_code_obj; + + if (json_object_object_get_ex(root, "key_code", &key_code_obj) && + json_object_object_get_ex(root, "state_code", &state_code_obj)) { + + *key_code = json_object_get_int(key_code_obj); + *is_pressed = json_object_get_int(state_code_obj); + + if (g_verbose) { + printf("Parsed key event: key_code=%d, is_pressed=%d\n", *key_code, *is_pressed); + } + + json_object_put(root); + return 0; + } + + json_object_put(root); + return -1; +} + +void cleanup() { + printf("Cleaning up...\n"); + + // Give threads a moment to finish naturally + usleep(500000); // 500ms + + // Free dynamically allocated filenames in multi config + for (int i = 0; i < 256; i++) { + if (g_sound_pack.multi_key_mappings[i].press) { + free(g_sound_pack.multi_key_mappings[i].press); + g_sound_pack.multi_key_mappings[i].press = NULL; + } + if (g_sound_pack.multi_key_mappings[i].release) { + free(g_sound_pack.multi_key_mappings[i].release); + g_sound_pack.multi_key_mappings[i].release = NULL; + } + } + + // Reset thread state + pthread_mutex_lock(&thread_mutex); + for (int i = 0; i < MAX_CONCURRENT_SOUNDS; i++) { + thread_active[i] = 0; + } + pthread_mutex_unlock(&thread_mutex); +} + +int main(int argc, char *argv[]) { + if (argc < 2 || argc > 4) { + fprintf(stderr, "Usage: %s [volume] [verbose]\n", argv[0]); + fprintf(stderr, " volume: 0-100 (default: 50)\n"); + fprintf(stderr, " verbose: 1 to enable verbose output (default: 0)\n"); + return 1; + } + + // Set volume + if (argc >= 3) { + int volume_percent = atoi(argv[2]); + if (volume_percent < 0) volume_percent = 0; + if (volume_percent > 100) volume_percent = 100; + g_volume = volume_percent / 100.0f; + printf("Volume set to: %d%%\n", volume_percent); + } else { + printf("Volume set to: 50%% (default)\n"); + } + + // Set verbose mode + if (argc >= 4) { + g_verbose = atoi(argv[3]); + if (g_verbose) { + printf("Verbose mode enabled\n"); + } + } + + // Load sound configuration + if (load_sound_config(argv[1]) != 0) { + fprintf(stderr, "Failed to load sound configuration\n"); + return 1; + } + + // Initialize audio + if (init_audio() != 0) { + fprintf(stderr, "Failed to initialize audio\n"); + return 1; + } + + // printf("Keyboard sound player initialized. Listening for key events...\n"); + // printf("Max concurrent sounds: %d\n", MAX_CONCURRENT_SOUNDS); + // printf("Waiting for input on stdin...\n"); + // fflush(stdout); + + // Add timeout for debugging + fd_set readfds; + struct timeval timeout; + + // Read JSON lines from stdin with timeout + char line[MAX_LINE_LENGTH]; + while (1) { + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + + timeout.tv_sec = 1; // 1 second timeout + timeout.tv_usec = 0; + + int ready = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &timeout); + + if (ready == -1) { + perror("select"); + break; + } else if (ready == 0) { + // Timeout - continue waiting + if (g_verbose) { + printf("Waiting for input...\n"); + } + continue; + } + + if (FD_ISSET(STDIN_FILENO, &readfds)) { + if (fgets(line, sizeof(line), stdin) == NULL) { + if (feof(stdin)) { + printf("EOF reached on stdin\n"); + } else { + perror("fgets"); + } + break; + } + + int key_code, is_pressed; + if (parse_keyboard_event(line, &key_code, &is_pressed) == 0) { + play_sound_segment(key_code, is_pressed); + } + } + } + + cleanup(); + return 0; +} diff --git a/keyvibe.c b/keyvibe.c new file mode 100644 index 0000000..c288f78 --- /dev/null +++ b/keyvibe.c @@ -0,0 +1,435 @@ +#define _POSIX_C_SOURCE 200809L + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PATH_LENGTH 512 +#define AUDIO_BASE_DIR KeyVibe_DATA_DIR "/audio" +#define USER_CONFIG_FILENAME ".keyvibe.json" + +// Global variables for cleanup +pid_t keyboard_pid = 0; +pid_t sound_pid = 0; + +void print_usage(const char *program_name) { + printf("KeyVibe - Mechanical Keyboard Sound Simulator\n\n"); + printf("Usage: %s [OPTIONS]\n\n", program_name); + printf("Options:\n"); + printf(" -s, --sound SOUND_NAME Select sound pack (default: eg-oreo)\n"); + printf(" -V, --volume VOLUME Set volume [0-100] (default: 50)\n"); + printf(" -c, --override-config Apply -s/-V to override loaded config\n"); + printf(" -l, --list List available sound packs\n"); + printf(" -h, --help Show this help message\n"); + printf(" -v, --verbose Enable verbose output\n"); + printf("\nConfiguration:\n"); + printf(" Reads ~/.keyvibe.json if present. On first run, prompts to create it.\n"); + printf("\nExamples:\n"); + printf(" %s # Use default sound (eg-oreo)\n", + program_name); + printf(" %s -s cherrymx-blue-abs # Use Cherry MX Blue ABS sound\n", + program_name); + printf(" %s -l # List all available sounds\n", + program_name); + printf("\nPress Ctrl+C to exit.\n"); +} + +int list_sound_packs() { + DIR *dir; + struct dirent *entry; + char path[MAX_PATH_LENGTH]; + struct stat st; + + dir = opendir(AUDIO_BASE_DIR); + if (dir == NULL) { + fprintf(stderr, "Error: Cannot open audio directory '%s'\n", + AUDIO_BASE_DIR); + fprintf(stderr, "Make sure you're running from the correct directory.\n"); + return 1; + } + + printf("Available sound packs:\n"); + printf("======================\n"); + + while ((entry = readdir(dir)) != NULL) { + // Skip . and .. directories + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + // Build full path + snprintf(path, sizeof(path), "%s/%s", AUDIO_BASE_DIR, entry->d_name); + + // Use stat to check if it's a directory + if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { + printf(" %s\n", entry->d_name); + } + } + + closedir(dir); + return 0; +} + +int validate_sound_pack(const char *sound_name) { + char config_path[MAX_PATH_LENGTH]; + char sound_path[MAX_PATH_LENGTH]; + + snprintf(config_path, sizeof(config_path), "%s/%s/config.json", + AUDIO_BASE_DIR, sound_name); + snprintf(sound_path, sizeof(sound_path), "%s/%s", AUDIO_BASE_DIR, sound_name); + + // Check if directory exists + if (access(sound_path, F_OK) != 0) { + fprintf(stderr, "Error: Sound pack '%s' not found in %s/\n", sound_name, + AUDIO_BASE_DIR); + fprintf(stderr, "Use --list to see available sound packs.\n"); + return 0; + } + + // Check if config.json exists + if (access(config_path, R_OK) != 0) { + fprintf(stderr, "Error: Config file not found: %s\n", config_path); + return 0; + } + + return 1; +} + +void cleanup_processes(int sig) { + (void)sig; // Suppress unused parameter warning + + printf("\nShutting down KeyVibe...\n"); + + if (sound_pid > 0) { + kill(sound_pid, SIGTERM); + waitpid(sound_pid, NULL, 0); + } + + if (keyboard_pid > 0) { + kill(keyboard_pid, SIGTERM); + waitpid(keyboard_pid, NULL, 0); + } + + exit(0); +} + +// Function to check if sudo credentials are cached +int check_sudo_cached() { + int status = system("sudo -n true 2>/dev/null"); + return WEXITSTATUS(status) == 0; +} + +// Function to prompt for sudo password if needed +int ensure_sudo_access() { + if (check_sudo_cached()) { + return 1; // Already have sudo access + } + + printf("This program requires sudo access to monitor keyboard events.\n"); + printf("Please enter your password when prompted:\n"); + + int status = system("sudo -v"); + if (WEXITSTATUS(status) != 0) { + fprintf(stderr, "Error: Failed to obtain sudo access\n"); + return 0; + } + + return 1; +} + +static char *get_user_config_path(char *buffer, size_t buflen) { + const char *home = getenv("HOME"); + if (!home || strlen(home) == 0) { + struct passwd *pw = getpwuid(getuid()); + if (pw && pw->pw_dir) home = pw->pw_dir; + } + if (!home) { + return NULL; + } + snprintf(buffer, buflen, "%s/%s", home, USER_CONFIG_FILENAME); + return buffer; +} + +static int write_user_config(const char *path, const char *sound, int volume) { + json_object *root = json_object_new_object(); + if (!root) return 0; + json_object_object_add(root, "sound", json_object_new_string(sound)); + json_object_object_add(root, "volume", json_object_new_int(volume)); + const char *json_str = json_object_to_json_string_ext(root, JSON_C_TO_STRING_PRETTY); + FILE *f = fopen(path, "w"); + if (!f) { json_object_put(root); return 0; } + fprintf(f, "%s\n", json_str); + fclose(f); + json_object_put(root); + return 1; +} + +static int read_user_config(const char *path, char **out_sound, int *out_volume) { + FILE *f = fopen(path, "r"); + if (!f) return 0; + fseek(f, 0, SEEK_END); + long sz = ftell(f); + rewind(f); + char *buf = malloc(sz + 1); + if (!buf) { fclose(f); return 0; } + fread(buf, 1, sz, f); + buf[sz] = '\0'; + fclose(f); + json_object *root = json_tokener_parse(buf); + free(buf); + if (!root) return 0; + json_object *o; + if (json_object_object_get_ex(root, "sound", &o)) { + const char *s = json_object_get_string(o); + if (s) *out_sound = strdup(s); + } + if (json_object_object_get_ex(root, "volume", &o)) { + *out_volume = json_object_get_int(o); + } + json_object_put(root); + return 1; +} + +int main(int argc, char *argv[]) { + char *sound_name = "eg-oreo"; // Default sound pack + int verbose = 0; + int list_sounds = 0; + + // Parse command line arguments + static struct option long_options[] = {{"sound", required_argument, 0, 's'}, + {"volume", required_argument, 0, 'V'}, + {"override-config", no_argument, 0, 'c'}, + {"list", no_argument, 0, 'l'}, + {"help", no_argument, 0, 'h'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0}}; + + int volume = 50; + int override_config = 0; + char *cli_sound = NULL; + int cli_volume = -1; + + // Load user config if present (pre-parse so CLI can override) + char user_cfg_path[MAX_PATH_LENGTH]; + if (get_user_config_path(user_cfg_path, sizeof(user_cfg_path))) { + if (access(user_cfg_path, R_OK) == 0) { + char *cfg_sound = NULL; int cfg_volume = volume; + if (read_user_config(user_cfg_path, &cfg_sound, &cfg_volume)) { + if (cfg_sound) { sound_name = cfg_sound; } + volume = cfg_volume; + } + } + } + + int opt; + while ((opt = getopt_long(argc, argv, "s:V:clhv", long_options, NULL)) != -1) { + switch (opt) { + case 's': + cli_sound = optarg; + break; + case 'V': + cli_volume = atoi(optarg); + if (cli_volume < 0) + cli_volume = 0; + if (cli_volume > 100) + cli_volume = 100; + break; + case 'c': + override_config = 1; + break; + case 'l': + list_sounds = 1; + break; + case 'h': + print_usage(argv[0]); + return 0; + case 'v': + verbose = 1; + break; + default: + print_usage(argv[0]); + return 1; + } + } + + // Handle list command + if (list_sounds) { + return list_sound_packs(); + } + + // Apply CLI overrides only if -c/--override-config was provided + if (override_config) { + if (cli_sound != NULL) sound_name = cli_sound; + if (cli_volume >= 0) volume = cli_volume; + } + + // If no config file existed, create one with defaults + if (get_user_config_path(user_cfg_path, sizeof(user_cfg_path))) { + if (access(user_cfg_path, F_OK) != 0) { + // Use current values (defaults or CLI overrides) for initial file + if (!write_user_config(user_cfg_path, sound_name, volume)) { + fprintf(stderr, "Warning: Failed to write %s\n", user_cfg_path); + } else if (verbose) { + fprintf(stderr, "Created default config %s\n", user_cfg_path); + } + } + } + + // Validate sound pack + if (!validate_sound_pack(sound_name)) { + return 1; + } + + // No sudo pre-check; we'll run without sudo by default + + // Check if required executables exist + char get_key_presses_path[MAX_PATH_LENGTH]; + char sound_player_path[MAX_PATH_LENGTH]; + + snprintf(get_key_presses_path, sizeof(get_key_presses_path), + "%s/get_key_presses", KeyVibe_BIN_DIR); + snprintf(sound_player_path, sizeof(sound_player_path), + "%s/keyboard_sound_player", KeyVibe_BIN_DIR); + + if (access(get_key_presses_path, X_OK) != 0) { + fprintf(stderr, "Error: Cannot find or execute %s\n", get_key_presses_path); + return 1; + } + + if (access(sound_player_path, X_OK) != 0) { + fprintf(stderr, "Error: Cannot find or execute %s\n", sound_player_path); + return 1; + } + + // Setup signal handler for cleanup + signal(SIGINT, cleanup_processes); + signal(SIGTERM, cleanup_processes); + + // Build paths + char config_path[MAX_PATH_LENGTH]; + char sound_dir[MAX_PATH_LENGTH]; + + snprintf(config_path, sizeof(config_path), "%s/%s/config.json", + AUDIO_BASE_DIR, sound_name); + snprintf(sound_dir, sizeof(sound_dir), "%s/%s", AUDIO_BASE_DIR, sound_name); + + if (verbose) { + printf("KeyVibe starting...\n"); + printf("Sound pack: %s\n", sound_name); + printf("Config file: %s\n", config_path); + printf("Working directory: %s\n", sound_dir); + printf("Press Ctrl+C to exit.\n\n"); + } else { + printf("KeyVibe started with sound pack: %s\n", sound_name); + printf("Press Ctrl+C to exit.\n"); + } + + // Create pipe for communication + int pipefd[2]; + if (pipe(pipefd) == -1) { + perror("pipe"); + return 1; + } + + // Fork sound player process FIRST + sound_pid = fork(); + if (sound_pid == -1) { + perror("fork"); + return 1; + } + + if (sound_pid == 0) { + // Child process: sound player + close(pipefd[1]); // Close write end + + // Redirect stdin from pipe + dup2(pipefd[0], STDIN_FILENO); + close(pipefd[0]); + + // Change to sound directory (so relative paths work) + if (chdir(sound_dir) != 0) { + perror("chdir"); + exit(1); + } + + if (verbose) { + fprintf(stderr, "Starting sound player...\n"); + } + + char volume_str[32]; + snprintf(volume_str, sizeof(volume_str), "%d", volume); + char verbose_str[8]; + snprintf(verbose_str, sizeof(verbose_str), "%d", verbose); + execl(sound_player_path, "keyboard_sound_player", "config.json", volume_str, + verbose_str, (char *)NULL); + perror("execl keyboard_sound_player"); + exit(1); + } + + // Then fork keyboard listener process (sudo) + keyboard_pid = fork(); + if (keyboard_pid == -1) { + perror("fork"); + kill(sound_pid, SIGTERM); + return 1; + } + + if (keyboard_pid == 0) { + // Child process: keyboard listener + close(pipefd[0]); // Close read end + + // Redirect stdout to pipe + dup2(pipefd[1], STDOUT_FILENO); + close(pipefd[1]); + + if (verbose) { + fprintf(stderr, "Starting keyboard listener...\n"); + } + + execl(get_key_presses_path, "get_key_presses", (char *)NULL); + perror("execl get_key_presses"); + exit(1); + } + + // Parent process: wait for children + close(pipefd[0]); + close(pipefd[1]); + + int status; + pid_t finished_pid; + + // Wait for either child to exit + while ((finished_pid = wait(&status)) > 0) { + if (finished_pid == keyboard_pid) { + printf("Keyboard listener exited with status %d\n", WEXITSTATUS(status)); + if (WIFSIGNALED(status)) { + printf("Keyboard listener killed by signal %d\n", WTERMSIG(status)); + } + keyboard_pid = 0; + if (sound_pid > 0) { + kill(sound_pid, SIGTERM); + } + } else if (finished_pid == sound_pid) { + printf("Sound player exited with status %d\n", WEXITSTATUS(status)); + if (WIFSIGNALED(status)) { + printf("Sound player killed by signal %d\n", WTERMSIG(status)); + } + sound_pid = 0; + if (keyboard_pid > 0) { + kill(keyboard_pid, SIGTERM); + } + } + } + + printf("KeyVibe exited.\n"); + return 0; +}