@@ -12,6 +12,7 @@ object GestureCommandMapper {
1212 enum class MultiplexerType {
1313 TMUX ,
1414 SCREEN ,
15+ ZELLIJ ,
1516 NONE
1617 }
1718
@@ -33,107 +34,193 @@ object GestureCommandMapper {
3334
3435 /* *
3536 * Get the command sequence for a specific gesture and multiplexer
37+ * @param gestureType The gesture that was detected
38+ * @param multiplexerType The multiplexer type (tmux, screen, zellij, or none)
39+ * @param customPrefix Optional custom prefix notation (e.g., "C-a", "C-Space")
40+ * @return Byte sequence to send, or null if not mapped
3641 */
37- fun getCommand (gestureType : GestureType , multiplexerType : MultiplexerType ): ByteArray? {
42+ fun getCommand (
43+ gestureType : GestureType ,
44+ multiplexerType : MultiplexerType ,
45+ customPrefix : String? = null
46+ ): ByteArray? {
47+ // If custom prefix specified, use it with multiplexer commands
48+ val prefix = if (! customPrefix.isNullOrEmpty()) {
49+ PrefixParser .parse(customPrefix) ? : getDefaultPrefix(multiplexerType)
50+ } else {
51+ getDefaultPrefix(multiplexerType)
52+ }
53+
54+ if (prefix.isEmpty()) {
55+ return null // NONE multiplexer
56+ }
57+
3858 return when (multiplexerType) {
39- MultiplexerType .TMUX -> getTmuxCommand(gestureType)
40- MultiplexerType .SCREEN -> getScreenCommand(gestureType)
59+ MultiplexerType .TMUX -> getTmuxCommand(gestureType, prefix)
60+ MultiplexerType .SCREEN -> getScreenCommand(gestureType, prefix)
61+ MultiplexerType .ZELLIJ -> getZellijCommand(gestureType, prefix)
4162 MultiplexerType .NONE -> null
4263 }
4364 }
4465
66+ /* *
67+ * Get default prefix for multiplexer type
68+ */
69+ private fun getDefaultPrefix (multiplexerType : MultiplexerType ): ByteArray {
70+ return when (multiplexerType) {
71+ MultiplexerType .TMUX -> byteArrayOf(0x02 .toByte()) // Ctrl+B
72+ MultiplexerType .SCREEN -> byteArrayOf(0x01 .toByte()) // Ctrl+A
73+ MultiplexerType .ZELLIJ -> byteArrayOf(0x07 .toByte()) // Ctrl+G
74+ MultiplexerType .NONE -> byteArrayOf()
75+ }
76+ }
77+
4578 /* *
4679 * Get tmux command sequence for gesture
47- * tmux uses Ctrl+B as prefix
80+ * @param gestureType The gesture detected
81+ * @param prefix The prefix key(s) to use (default or custom)
4882 */
49- private fun getTmuxCommand (gestureType : GestureType ): ByteArray? {
50- val CTRL_B = 0x02 .toByte()
51-
83+ private fun getTmuxCommand (gestureType : GestureType , prefix : ByteArray ): ByteArray? {
5284 return when (gestureType) {
5385 // Window navigation
54- GestureType .TWO_FINGER_SWIPE_RIGHT -> byteArrayOf(CTRL_B , ' n' .code.toByte()) // next window
55- GestureType .TWO_FINGER_SWIPE_LEFT -> byteArrayOf(CTRL_B , ' p' .code.toByte()) // previous window
56- GestureType .TWO_FINGER_SWIPE_DOWN -> byteArrayOf(CTRL_B , ' c' .code.toByte()) // create window
57- GestureType .TWO_FINGER_SWIPE_UP -> byteArrayOf(CTRL_B , ' w' .code.toByte()) // list windows
86+ GestureType .TWO_FINGER_SWIPE_RIGHT -> prefix + byteArrayOf(' n' .code.toByte()) // next window
87+ GestureType .TWO_FINGER_SWIPE_LEFT -> prefix + byteArrayOf(' p' .code.toByte()) // previous window
88+ GestureType .TWO_FINGER_SWIPE_DOWN -> prefix + byteArrayOf(' c' .code.toByte()) // create window
89+ GestureType .TWO_FINGER_SWIPE_UP -> prefix + byteArrayOf(' w' .code.toByte()) // list windows
5890
5991 // Pane operations
60- GestureType .THREE_FINGER_SWIPE_RIGHT -> byteArrayOf(CTRL_B , ' o' .code.toByte()) // next pane
61- GestureType .THREE_FINGER_SWIPE_LEFT -> byteArrayOf(CTRL_B , ' ;' .code.toByte()) // last pane
62- GestureType .THREE_FINGER_SWIPE_DOWN -> byteArrayOf(CTRL_B , ' "' .code.toByte()) // split horizontal
63- GestureType .THREE_FINGER_SWIPE_UP -> byteArrayOf(CTRL_B , ' %' .code.toByte()) // split vertical
92+ GestureType .THREE_FINGER_SWIPE_RIGHT -> prefix + byteArrayOf(' o' .code.toByte()) // next pane
93+ GestureType .THREE_FINGER_SWIPE_LEFT -> prefix + byteArrayOf(' ;' .code.toByte()) // last pane
94+ GestureType .THREE_FINGER_SWIPE_DOWN -> prefix + byteArrayOf(' "' .code.toByte()) // split horizontal
95+ GestureType .THREE_FINGER_SWIPE_UP -> prefix + byteArrayOf(' %' .code.toByte()) // split vertical
6496
6597 // Zoom/detach
66- GestureType .PINCH_IN -> byteArrayOf(CTRL_B , ' z' .code.toByte()) // zoom pane
67- GestureType .PINCH_OUT -> byteArrayOf(CTRL_B , ' d' .code.toByte()) // detach
98+ GestureType .PINCH_IN -> prefix + byteArrayOf(' z' .code.toByte()) // zoom pane
99+ GestureType .PINCH_OUT -> prefix + byteArrayOf(' d' .code.toByte()) // detach
68100 }
69101 }
70102
71103 /* *
72104 * Get screen command sequence for gesture
73- * screen uses Ctrl+A as prefix
105+ * @param gestureType The gesture detected
106+ * @param prefix The prefix key(s) to use (default or custom)
74107 */
75- private fun getScreenCommand (gestureType : GestureType ): ByteArray? {
76- val CTRL_A = 0x01 .toByte()
77-
108+ private fun getScreenCommand (gestureType : GestureType , prefix : ByteArray ): ByteArray? {
78109 return when (gestureType) {
79110 // Window navigation
80- GestureType .THREE_FINGER_SWIPE_RIGHT -> byteArrayOf(CTRL_A , ' n' .code.toByte()) // next window
81- GestureType .THREE_FINGER_SWIPE_LEFT -> byteArrayOf(CTRL_A , ' p' .code.toByte()) // previous window
82- GestureType .THREE_FINGER_SWIPE_DOWN -> byteArrayOf(CTRL_A , ' c' .code.toByte()) // create window
83- GestureType .THREE_FINGER_SWIPE_UP -> byteArrayOf(CTRL_A , ' w' .code.toByte()) // list windows
111+ GestureType .THREE_FINGER_SWIPE_RIGHT -> prefix + byteArrayOf(' n' .code.toByte()) // next window
112+ GestureType .THREE_FINGER_SWIPE_LEFT -> prefix + byteArrayOf(' p' .code.toByte()) // previous window
113+ GestureType .THREE_FINGER_SWIPE_DOWN -> prefix + byteArrayOf(' c' .code.toByte()) // create window
114+ GestureType .THREE_FINGER_SWIPE_UP -> prefix + byteArrayOf(' w' .code.toByte()) // list windows
84115
85116 // Split operations
86- GestureType .TWO_FINGER_SWIPE_DOWN -> byteArrayOf(CTRL_A , ' S' .code.toByte()) // split horizontal
87- GestureType .TWO_FINGER_SWIPE_RIGHT -> byteArrayOf(CTRL_A , ' \t ' .code.toByte()) // next region
88- GestureType .TWO_FINGER_SWIPE_LEFT -> byteArrayOf(CTRL_A , ' \t ' .code.toByte()) // next region (same)
117+ GestureType .TWO_FINGER_SWIPE_DOWN -> prefix + byteArrayOf(' S' .code.toByte()) // split horizontal
118+ GestureType .TWO_FINGER_SWIPE_RIGHT -> prefix + byteArrayOf(' \t ' .code.toByte()) // next region
119+ GestureType .TWO_FINGER_SWIPE_LEFT -> prefix + byteArrayOf(' \t ' .code.toByte()) // next region (same)
89120
90121 // Detach
91- GestureType .PINCH_OUT -> byteArrayOf(CTRL_A , ' d' .code.toByte()) // detach
122+ GestureType .PINCH_OUT -> prefix + byteArrayOf(' d' .code.toByte()) // detach
92123
93124 // Not mapped
94125 GestureType .TWO_FINGER_SWIPE_UP ,
95126 GestureType .PINCH_IN -> null
96127 }
97128 }
98129
130+ /* *
131+ * Get zellij command sequence for gesture
132+ * @param gestureType The gesture detected
133+ * @param prefix The prefix key(s) to use (default or custom)
134+ */
135+ private fun getZellijCommand (gestureType : GestureType , prefix : ByteArray ): ByteArray? {
136+ return when (gestureType) {
137+ // Tab navigation
138+ GestureType .TWO_FINGER_SWIPE_RIGHT -> prefix + byteArrayOf(' n' .code.toByte()) // next tab
139+ GestureType .TWO_FINGER_SWIPE_LEFT -> prefix + byteArrayOf(' p' .code.toByte()) // previous tab
140+ GestureType .TWO_FINGER_SWIPE_DOWN -> prefix + byteArrayOf(' t' .code.toByte()) // new tab
141+ GestureType .TWO_FINGER_SWIPE_UP -> prefix + byteArrayOf(' w' .code.toByte()) // close tab
142+
143+ // Pane operations
144+ GestureType .THREE_FINGER_SWIPE_RIGHT -> prefix + byteArrayOf(' h' .code.toByte()) // next pane
145+ GestureType .THREE_FINGER_SWIPE_LEFT -> prefix + byteArrayOf(' l' .code.toByte()) // previous pane
146+ GestureType .THREE_FINGER_SWIPE_DOWN -> prefix + byteArrayOf(' s' .code.toByte()) // split horizontal
147+ GestureType .THREE_FINGER_SWIPE_UP -> prefix + byteArrayOf(' v' .code.toByte()) // split vertical
148+
149+ // Zoom/quit
150+ GestureType .PINCH_IN -> prefix + byteArrayOf(' z' .code.toByte()) // toggle fullscreen
151+ GestureType .PINCH_OUT -> prefix + byteArrayOf(' q' .code.toByte()) // quit
152+ }
153+ }
154+
99155 /* *
100156 * Get human-readable description of gesture command
101157 */
102- fun getDescription (gestureType : GestureType , multiplexerType : MultiplexerType ): String {
158+ fun getDescription (gestureType : GestureType , multiplexerType : MultiplexerType , customPrefix : String? = null): String {
159+ val prefixDesc = if (! customPrefix.isNullOrEmpty()) {
160+ PrefixParser .getDescription(customPrefix)
161+ } else {
162+ getDefaultPrefixDescription(multiplexerType)
163+ }
164+
103165 return when (multiplexerType) {
104- MultiplexerType .TMUX -> getTmuxDescription(gestureType)
105- MultiplexerType .SCREEN -> getScreenDescription(gestureType)
166+ MultiplexerType .TMUX -> getTmuxDescription(gestureType, prefixDesc)
167+ MultiplexerType .SCREEN -> getScreenDescription(gestureType, prefixDesc)
168+ MultiplexerType .ZELLIJ -> getZellijDescription(gestureType, prefixDesc)
106169 MultiplexerType .NONE -> " Gesture disabled"
107170 }
108171 }
109172
110- private fun getTmuxDescription (gestureType : GestureType ): String {
173+ private fun getDefaultPrefixDescription (multiplexerType : MultiplexerType ): String {
174+ return when (multiplexerType) {
175+ MultiplexerType .TMUX -> " Ctrl+B"
176+ MultiplexerType .SCREEN -> " Ctrl+A"
177+ MultiplexerType .ZELLIJ -> " Ctrl+G"
178+ MultiplexerType .NONE -> " "
179+ }
180+ }
181+
182+ private fun getTmuxDescription (gestureType : GestureType , prefix : String ): String {
111183 return when (gestureType) {
112- GestureType .TWO_FINGER_SWIPE_RIGHT -> " tmux: Next window (Ctrl+B n)"
113- GestureType .TWO_FINGER_SWIPE_LEFT -> " tmux: Previous window (Ctrl+B p)"
114- GestureType .TWO_FINGER_SWIPE_DOWN -> " tmux: Create window (Ctrl+B c)"
115- GestureType .TWO_FINGER_SWIPE_UP -> " tmux: List windows (Ctrl+B w)"
116- GestureType .THREE_FINGER_SWIPE_RIGHT -> " tmux: Next pane (Ctrl+B o)"
117- GestureType .THREE_FINGER_SWIPE_LEFT -> " tmux: Last pane (Ctrl+B ;)"
118- GestureType .THREE_FINGER_SWIPE_DOWN -> " tmux: Split horizontal (Ctrl+B \" )"
119- GestureType .THREE_FINGER_SWIPE_UP -> " tmux: Split vertical (Ctrl+B %)"
120- GestureType .PINCH_IN -> " tmux: Zoom pane (Ctrl+B z)"
121- GestureType .PINCH_OUT -> " tmux: Detach (Ctrl+B d)"
184+ GestureType .TWO_FINGER_SWIPE_RIGHT -> " tmux: Next window ($prefix n)"
185+ GestureType .TWO_FINGER_SWIPE_LEFT -> " tmux: Previous window ($prefix p)"
186+ GestureType .TWO_FINGER_SWIPE_DOWN -> " tmux: Create window ($prefix c)"
187+ GestureType .TWO_FINGER_SWIPE_UP -> " tmux: List windows ($prefix w)"
188+ GestureType .THREE_FINGER_SWIPE_RIGHT -> " tmux: Next pane ($prefix o)"
189+ GestureType .THREE_FINGER_SWIPE_LEFT -> " tmux: Last pane ($prefix ;)"
190+ GestureType .THREE_FINGER_SWIPE_DOWN -> " tmux: Split horizontal ($prefix \" )"
191+ GestureType .THREE_FINGER_SWIPE_UP -> " tmux: Split vertical ($prefix %)"
192+ GestureType .PINCH_IN -> " tmux: Zoom pane ($prefix z)"
193+ GestureType .PINCH_OUT -> " tmux: Detach ($prefix d)"
122194 }
123195 }
124196
125- private fun getScreenDescription (gestureType : GestureType ): String {
197+ private fun getScreenDescription (gestureType : GestureType , prefix : String ): String {
126198 return when (gestureType) {
127- GestureType .THREE_FINGER_SWIPE_RIGHT -> " screen: Next window (Ctrl+A n)"
128- GestureType .THREE_FINGER_SWIPE_LEFT -> " screen: Previous window (Ctrl+A p)"
129- GestureType .THREE_FINGER_SWIPE_DOWN -> " screen: Create window (Ctrl+A c)"
130- GestureType .THREE_FINGER_SWIPE_UP -> " screen: List windows (Ctrl+A w)"
131- GestureType .TWO_FINGER_SWIPE_DOWN -> " screen: Split horizontal (Ctrl+A S)"
132- GestureType .TWO_FINGER_SWIPE_RIGHT -> " screen: Next region (Ctrl+A Tab)"
133- GestureType .TWO_FINGER_SWIPE_LEFT -> " screen: Next region (Ctrl+A Tab)"
134- GestureType .PINCH_OUT -> " screen: Detach (Ctrl+A d)"
199+ GestureType .THREE_FINGER_SWIPE_RIGHT -> " screen: Next window ($prefix n)"
200+ GestureType .THREE_FINGER_SWIPE_LEFT -> " screen: Previous window ($prefix p)"
201+ GestureType .THREE_FINGER_SWIPE_DOWN -> " screen: Create window ($prefix c)"
202+ GestureType .THREE_FINGER_SWIPE_UP -> " screen: List windows ($prefix w)"
203+ GestureType .TWO_FINGER_SWIPE_DOWN -> " screen: Split horizontal ($prefix S)"
204+ GestureType .TWO_FINGER_SWIPE_RIGHT -> " screen: Next region ($prefix Tab)"
205+ GestureType .TWO_FINGER_SWIPE_LEFT -> " screen: Next region ($prefix Tab)"
206+ GestureType .PINCH_OUT -> " screen: Detach ($prefix d)"
135207 GestureType .TWO_FINGER_SWIPE_UP ,
136208 GestureType .PINCH_IN -> " Not mapped for screen"
137209 }
138210 }
211+
212+ private fun getZellijDescription (gestureType : GestureType , prefix : String ): String {
213+ return when (gestureType) {
214+ GestureType .TWO_FINGER_SWIPE_RIGHT -> " zellij: Next tab ($prefix n)"
215+ GestureType .TWO_FINGER_SWIPE_LEFT -> " zellij: Previous tab ($prefix p)"
216+ GestureType .TWO_FINGER_SWIPE_DOWN -> " zellij: New tab ($prefix t)"
217+ GestureType .TWO_FINGER_SWIPE_UP -> " zellij: Close tab ($prefix w)"
218+ GestureType .THREE_FINGER_SWIPE_RIGHT -> " zellij: Next pane ($prefix h)"
219+ GestureType .THREE_FINGER_SWIPE_LEFT -> " zellij: Previous pane ($prefix l)"
220+ GestureType .THREE_FINGER_SWIPE_DOWN -> " zellij: Split horizontal ($prefix s)"
221+ GestureType .THREE_FINGER_SWIPE_UP -> " zellij: Split vertical ($prefix v)"
222+ GestureType .PINCH_IN -> " zellij: Toggle fullscreen ($prefix z)"
223+ GestureType .PINCH_OUT -> " zellij: Quit ($prefix q)"
224+ }
225+ }
139226}
0 commit comments