From fd883c1391c8689371ec64bc733adf230efcff1c Mon Sep 17 00:00:00 2001 From: Albert Graef Date: Wed, 12 Sep 2018 19:57:03 +0200 Subject: [PATCH] Allow up to four different internal shift keys. --- examples/Maschine.midizaprc | 102 ++++++++--------- midizap.c | 12 +- midizap.h | 35 +++--- readconfig.c | 213 +++++++++++++++++++++--------------- 4 files changed, 203 insertions(+), 159 deletions(-) diff --git a/examples/Maschine.midizaprc b/examples/Maschine.midizaprc index c74cea4..a5f60e1 100644 --- a/examples/Maschine.midizaprc +++ b/examples/Maschine.midizaprc @@ -22,9 +22,9 @@ SYSTEM_PASSTHROUGH # pass through MCP feedback [MIDI] -# The Mk3's dedicated shift key is used to provide alternative functions -# to some of the buttons and the faders. -?F2 SHIFT RELEASE SHIFT +# We use the Mk3's dedicated SHIFT button as our primary shift key, to provide +# alternative functions to some of the buttons and the faders. +?F2 SHIFT RELEASE SHIFT # transport (assigned to the transport section on the bottom left) F#5 A7 # Stop @@ -69,19 +69,23 @@ A#4 B5 # Control (MOD key) B4 C6 # Option (PERFORM key) D3 C#6 # Alt/Cmd (NOTES key) -# big encoder press/left/right/up/down assigned to the zoom/cursor keys +# big encoder press/left/right/up/down is assigned to the zoom/cursor keys D2 C8 # Up E2 C#8 # Down D#2 D8 # Left C#2 D#8 # Right C2 E8 # Zoom -# The Mk3 only has one row of dedicated "channel buttons" on the top, which we -# use for channel select. But we'd also like to have buttons for rec, solo and -# mute, so we (rather arbitrarily) bind them to the shifted A..H and grid -# buttons. +# The Mk3 has one row of dedicated "channel buttons" at the top, right above +# the display. Since we'd also like to use these for the channel-based +# rec/solo/mute functions, we combine them with the SELECT, SOLO and MUTE +# buttons as additional shift keys. -# track select (top row right above the display) +?F#4 SHIFT2 RELEASE SHIFT2 +?G4 SHIFT3 RELEASE SHIFT3 +?G#4 SHIFT4 RELEASE SHIFT4 + +# top row, unshifted: track select G6 C2 G#6 C#2 A6 D2 @@ -91,9 +95,38 @@ C7 F2 C#7 F#2 D7 G2 -# shifted top row -# We assign these to the function keys F1..F8 here, but of course you can -# remap these as needed. +# SELECT: rec +2^G6 C0 +2^G#6 C#0 +2^A6 D0 +2^A#6 D#0 +2^B6 E0 +2^C7 F0 +2^C#7 F#0 +2^D7 G0 + +# SOLO: solo +3^G6 G#0 +3^G#6 A0 +3^A6 A#0 +3^A#6 B0 +3^B6 C1 +3^C7 C#1 +3^C#7 D1 +3^D7 D#1 + +# MUTE: mute +4^G6 E1 +4^G#6 F1 +4^A6 F#1 +4^A#6 G1 +4^B6 G#1 +4^C7 A1 +4^C#7 A#1 +4^D7 B1 + +# We also assign these to the function keys F1..F8 when shifted. You may want +# to remap these as needed. ^G6 F#4 ^G#6 G4 ^A6 G#4 @@ -103,40 +136,10 @@ D7 G2 ^C#7 C5 ^D7 C#5 -# shifted A..H keys = rec -^F#2 C0 -^G2 C#0 -^G#2 D0 -^A2 D#0 -^A#2 E0 -^B2 F0 -^C3 F#0 -^C#3 G0 - -# upper half of grid, shifted = solo -^C4-10 G#0 -^C#4-10 A0 -^D4-10 A#0 -^D#4-10 B0 -^G#3-10 C1 -^A3-10 C#1 -^A#3-10 D1 -^B3-10 D#1 - -# lower half of grid, shifted = mute -^E3-10 E1 -^F3-10 F1 -^F#3-10 F#1 -^G3-10 G1 -^C3-10 G#1 -^C#3-10 A1 -^D3-10 A#1 -^D#3-10 B1 - -# The unshifted grid buttons are passed through unchanged, so that you can -# still use them as drum pads (provided that you filter out all MIDI channels -# except channel 10). Note that we use mod translations here, in order to -# preserve the velocities. +# The grid buttons are passed through unchanged, so that you can still use +# them as drum pads (provided that you filter out all MIDI channels except +# channel 10). Note that we use mod translations here, in order to preserve +# the velocities. C3[]-10 C3-10 C#3[]-10 C#3-10 @@ -155,10 +158,9 @@ C#4[]-10 C#4-10 D4[]-10 D4-10 D#4[]-10 D#4-10 -# Map the unshifted A..H buttons to program changes on channel 10 so that you -# can quickly switch the sounds of your drumkit, drum patterns etc. (This is -# just an example, you might want to disable these or remap them as you see -# fit.) +# Map the A..H buttons to program changes on channel 10 so that you can +# quickly switch the sounds of your drumkit, drum patterns etc. (This is just +# an example, you might want to disable these or remap them as you see fit.) F#2 PC0-10 G2 PC1-10 diff --git a/midizap.c b/midizap.c index 7d0964d..6db9d7d 100644 --- a/midizap.c +++ b/midizap.c @@ -316,8 +316,9 @@ static stroke *find_stroke_data(stroke_data *sd, if (mod) *mod = sd[i].mod; return sd[i].s[index]; } else if (sd[i].chan > chan || - (sd[i].chan == chan && sd[i].data > data)) + (sd[i].chan == chan && sd[i].data > data)) { return NULL; + } } return NULL; } else { @@ -520,7 +521,9 @@ static int note_octave(int n) static char *debug_key(translation *tr, char *name, int status, int chan, int data, int dir) { - char *prefix = shift?"^":"", *suffix = ""; + char prefix[10] = ""; + if (shift) sprintf(prefix, "%d^", shift); + char *suffix = ""; strcpy(name, "??"); switch (status) { case 0x90: { @@ -785,7 +788,10 @@ send_strokes(translation *tr, uint8_t portno, int status, int chan, nkeys++; } else if (s->shift) { // toggle shift status - shift = !shift; + if (shift != s->shift) + shift = s->shift; + else + shift = 0; } else if (!s->status) { // do nothing (NOP) ; diff --git a/midizap.h b/midizap.h index 971e4ae..2c3ac77 100644 --- a/midizap.h +++ b/midizap.h @@ -83,6 +83,9 @@ typedef struct _stroke_data { uint8_t mod; } stroke_data; +#define N_SHIFTS 4 // number of distinct shift states +#define N_ST (N_SHIFTS+1) + typedef struct _translation { struct _translation *next; char *name; @@ -90,22 +93,24 @@ typedef struct _translation { regex_t regex; uint8_t portno; // these are indexed by shift status - stroke_data *note[2]; - stroke_data *notes[2]; - stroke_data *pc[2]; - stroke_data *cc[2]; - stroke_data *ccs[2]; - stroke_data *pb[2]; - stroke_data *pbs[2]; - stroke_data *kp[2]; - stroke_data *kps[2]; - stroke_data *cp[2]; - stroke_data *cps[2]; + stroke_data *note[N_ST]; + stroke_data *notes[N_ST]; + stroke_data *pc[N_ST]; + stroke_data *cc[N_ST]; + stroke_data *ccs[N_ST]; + stroke_data *pb[N_ST]; + stroke_data *pbs[N_ST]; + stroke_data *kp[N_ST]; + stroke_data *kps[N_ST]; + stroke_data *cp[N_ST]; + stroke_data *cps[N_ST]; // actual and allocated sizes (can be at most 16*128) - uint16_t n_note[2], n_notes[2], n_pc[2], n_cc[2], n_ccs[2], - n_pb[2], n_pbs[2], n_kp[2], n_kps[2], n_cp[2], n_cps[2]; - uint16_t a_note[2], a_notes[2], a_pc[2], a_cc[2], a_ccs[2], - a_pb[2], a_pbs[2], a_kp[2], a_kps[2], a_cp[2], a_cps[2]; + uint16_t n_note[N_ST], n_notes[N_ST], n_pc[N_ST], + n_cc[N_ST], n_ccs[N_ST], n_pb[N_ST], n_pbs[N_ST], + n_kp[N_ST], n_kps[N_ST], n_cp[N_ST], n_cps[N_ST]; + uint16_t a_note[N_ST], a_notes[N_ST], a_pc[N_ST], + a_cc[N_ST], a_ccs[N_ST], a_pb[N_ST], a_pbs[N_ST], + a_kp[N_ST], a_kps[N_ST], a_cp[N_ST], a_cps[N_ST]; } translation; extern void reload_callback(void); diff --git a/readconfig.c b/readconfig.c index f702d60..db30ac9 100644 --- a/readconfig.c +++ b/readconfig.c @@ -427,7 +427,7 @@ finish_translation_section(translation *tr) int k; if (tr) { - for (k=0; k<2; k++) { + for (k=0; kpc[k], &tr->n_pc[k], &tr->a_pc[k]); finish_stroke_data(&tr->note[k], &tr->n_note[k], &tr->a_note[k]); finish_stroke_data(&tr->cc[k], &tr->n_cc[k], &tr->a_cc[k]); @@ -448,7 +448,7 @@ free_translation_section(translation *tr) if (!tr->is_default) { regfree(&tr->regex); } - for (k=0; k<2; k++) { + for (k=0; kpc[k], tr->n_pc[k]); free_stroke_data(tr->note[k], tr->n_note[k]); free_stroke_data(tr->cc[k], tr->n_cc[k]); @@ -625,7 +625,7 @@ print_stroke(stroke *s, int mod, int step, int n_steps, int *steps, int val) } printf("%s/%c ", str, s->press ? 'D' : 'U'); } else if (s->shift) { - printf("SHIFT "); + printf("SHIFT%d ", s->shift); } else if (!s->status) { printf("NOP "); } else { @@ -752,8 +752,8 @@ stroke **first_stroke; stroke *last_stroke; stroke **press_first_stroke; stroke **release_first_stroke; -stroke **alt_press_stroke; -stroke **alt_release_stroke; +stroke **alt_press_stroke[N_SHIFTS]; +stroke **alt_release_stroke[N_SHIFTS]; int is_keystroke, is_bidirectional, is_anyshift, is_midi, is_nop, mode; char *current_translation; char *key_name; @@ -784,12 +784,12 @@ append_stroke(KeySym sym, int press) } void -append_shift(void) +append_shift(int shift) { stroke *s = (stroke *)allocate(sizeof(stroke)); memset(s, 0, sizeof(stroke)); - s->shift = 1; + s->shift = shift; if (*first_stroke) { last_stroke->next = s; } else { @@ -1265,10 +1265,23 @@ parse_midi(char *tok, char *s, int lhs, int mode, } } + +static int chk(stroke **s) +{ + return !s || *s; +} + +static int chks(stroke **s[N_SHIFTS]) +{ + for (int i = 0; i < N_SHIFTS; i++) + if (chk(s[i])) return 1; + return 0; +} + int start_translation(translation *tr, char *which_key) { - int k, status, data, step, n_steps, *steps, incr, dir, mod, swap; + int status, data, step, n_steps, *steps, incr, dir, mod, swap; char buf[100]; //printf("start_translation(%s)\n", which_key); @@ -1284,8 +1297,19 @@ start_translation(translation *tr, char *which_key) regular_key_down = 0; modifier_count = 0; midi_channel = 0; - k = *which_key == '^' || (is_anyshift = *which_key == '?'); - if (parse_midi(which_key+k, buf, 1, 0, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod, &swap)) { + int k = 0, offs = 0; + if (isdigit(which_key[0]) && which_key[1] == '^') { + offs = 2; k = which_key[0]-'0'; + if (k<1 || k>N_SHIFTS) { + fprintf(stderr, "invalid shift key: [%s]%s\n", current_translation, which_key); + return 1; + } + } else if (*which_key == '^') { + offs = k = 1; + } else if ((is_anyshift = *which_key == '?')) { + offs = 1; k = 0; + } + if (parse_midi(which_key+offs, buf, 1, 0, &status, &data, &step, &n_steps, &steps, &incr, &dir, &mod, &swap)) { int chan = status & 0x0f; mode = incr?0:mod?2:1; switch (status & 0xf0) { @@ -1297,31 +1321,31 @@ start_translation(translation *tr, char *which_key) return 1; } first_stroke = find_notes(tr, k, chan, data, dir>0, step); - if (is_anyshift) { - alt_press_stroke = find_notes(tr, 0, chan, data, dir>0, step); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_notes(tr, i+1, chan, data, dir>0, step); } if (!dir) { is_bidirectional = 1; release_first_stroke = find_notes(tr, k, chan, data, 1, step); - if (is_anyshift) { - alt_release_stroke = find_notes(tr, 0, chan, data, 1, step); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_release_stroke[i] = find_notes(tr, i+1, chan, data, 1, step); } } } else if (mod) { // note mod first_stroke = find_note(tr, k, chan, data, 0, mod, step, n_steps, steps); - if (is_anyshift) { - alt_press_stroke = find_note(tr, 0, chan, data, 0, mod, - step, n_steps, steps); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_note(tr, i+1, chan, data, 0, mod, + step, n_steps, steps); } } else { // note on/off first_stroke = find_note(tr, k, chan, data, 0, 0, 0, 0, 0); release_first_stroke = find_note(tr, k, chan, data, 1, 0, 0, 0, 0); - if (is_anyshift) { - alt_press_stroke = find_note(tr, 0, chan, data, 0, 0, 0, 0, 0); - alt_release_stroke = find_note(tr, 0, chan, data, 1, 0, 0, 0, 0); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_note(tr, i+1, chan, data, 0, 0, 0, 0, 0); + alt_release_stroke[i] = find_note(tr, i+1, chan, data, 1, 0, 0, 0, 0); } is_keystroke = 1; } @@ -1334,9 +1358,9 @@ start_translation(translation *tr, char *which_key) // the corresponding "release" sequence. first_stroke = find_pc(tr, k, chan, data, 0); release_first_stroke = find_pc(tr, k, chan, data, 1); - if (is_anyshift) { - alt_press_stroke = find_pc(tr, 0, chan, data, 0); - alt_release_stroke = find_pc(tr, 0, chan, data, 1); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_pc(tr, i+1, chan, data, 0); + alt_release_stroke[i] = find_pc(tr, i+1, chan, data, 1); } is_keystroke = 1; break; @@ -1348,8 +1372,8 @@ start_translation(translation *tr, char *which_key) return 1; } first_stroke = find_ccs(tr, k, chan, data, dir>0, step, incr>1); - if (is_anyshift) { - alt_press_stroke = find_ccs(tr, 0, chan, data, dir>0, step, incr>1); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_ccs(tr, i+1, chan, data, dir>0, step, incr>1); } if (!dir) { // This is a bidirectional translation (=, ~). We first fill in the @@ -1361,25 +1385,25 @@ start_translation(translation *tr, char *which_key) // so that we can fill in that part later. is_bidirectional = 1; release_first_stroke = find_ccs(tr, k, chan, data, 1, step, incr>1); - if (is_anyshift) { - alt_release_stroke = find_ccs(tr, 0, chan, data, 1, step, incr>1); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_release_stroke[i] = find_ccs(tr, i+1, chan, data, 1, step, incr>1); } } } else if (mod) { // cc mod first_stroke = find_cc(tr, k, chan, data, 0, mod, step, n_steps, steps); - if (is_anyshift) { - alt_press_stroke = find_cc(tr, 0, chan, data, 0, mod, + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_cc(tr, i+1, chan, data, 0, mod, step, n_steps, steps); } } else { // cc on/off first_stroke = find_cc(tr, k, chan, data, 0, 0, 0, 0, 0); release_first_stroke = find_cc(tr, k, chan, data, 1, 0, 0, 0, 0); - if (is_anyshift) { - alt_press_stroke = find_cc(tr, 0, chan, data, 0, 0, 0, 0, 0); - alt_release_stroke = find_cc(tr, 0, chan, data, 1, 0, 0, 0, 0); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_cc(tr, i+1, chan, data, 0, 0, 0, 0, 0); + alt_release_stroke[i] = find_cc(tr, i+1, chan, data, 1, 0, 0, 0, 0); } is_keystroke = 1; } @@ -1392,31 +1416,31 @@ start_translation(translation *tr, char *which_key) return 1; } first_stroke = find_kps(tr, k, chan, data, dir>0, step); - if (is_anyshift) { - alt_press_stroke = find_kps(tr, 0, chan, data, dir>0, step); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_kps(tr, i+1, chan, data, dir>0, step); } if (!dir) { is_bidirectional = 1; release_first_stroke = find_kps(tr, k, chan, data, 1, step); - if (is_anyshift) { - alt_release_stroke = find_kps(tr, 0, chan, data, 1, step); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_release_stroke[i] = find_kps(tr, i+1, chan, data, 1, step); } } } else if (mod) { // kp mod first_stroke = find_kp(tr, k, chan, data, 0, mod, step, n_steps, steps); - if (is_anyshift) { - alt_press_stroke = find_kp(tr, 0, chan, data, 0, mod, - step, n_steps, steps); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_kp(tr, i+1, chan, data, 0, mod, + step, n_steps, steps); } } else { // kp on/off first_stroke = find_kp(tr, k, chan, data, 0, 0, 0, 0, 0); release_first_stroke = find_kp(tr, k, chan, data, 1, 0, 0, 0, 0); - if (is_anyshift) { - alt_press_stroke = find_kp(tr, 0, chan, data, 0, 0, 0, 0, 0); - alt_release_stroke = find_kp(tr, 0, chan, data, 1, 0, 0, 0, 0); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_kp(tr, i+1, chan, data, 0, 0, 0, 0, 0); + alt_release_stroke[i] = find_kp(tr, i+1, chan, data, 1, 0, 0, 0, 0); } is_keystroke = 1; } @@ -1429,31 +1453,31 @@ start_translation(translation *tr, char *which_key) return 1; } first_stroke = find_cps(tr, k, chan, dir>0, step); - if (is_anyshift) { - alt_press_stroke = find_cps(tr, 0, chan, dir>0, step); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_cps(tr, i+1, chan, dir>0, step); } if (!dir) { is_bidirectional = 1; release_first_stroke = find_cps(tr, k, chan, 1, step); - if (is_anyshift) { - alt_release_stroke = find_cps(tr, 0, chan, 1, step); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_release_stroke[i] = find_cps(tr, i+1, chan, 1, step); } } } else if (mod) { // cp mod first_stroke = find_cp(tr, k, chan, 0, mod, step, n_steps, steps); - if (is_anyshift) { - alt_press_stroke = find_cp(tr, 0, chan, 0, mod, + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_cp(tr, i+1, chan, 0, mod, step, n_steps, steps); } } else { // cp on/off first_stroke = find_cp(tr, k, chan, 0, 0, 0, 0, 0); release_first_stroke = find_cp(tr, k, chan, 1, 0, 0, 0, 0); - if (is_anyshift) { - alt_press_stroke = find_cp(tr, 0, chan, 0, 0, 0, 0, 0); - alt_release_stroke = find_cp(tr, 0, chan, 1, 0, 0, 0, 0); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_cp(tr, i+1, chan, 0, 0, 0, 0, 0); + alt_release_stroke[i] = find_cp(tr, i+1, chan, 1, 0, 0, 0, 0); } is_keystroke = 1; } @@ -1466,31 +1490,31 @@ start_translation(translation *tr, char *which_key) return 1; } first_stroke = find_pbs(tr, k, chan, dir>0, step); - if (is_anyshift) { - alt_press_stroke = find_pbs(tr, 0, chan, dir>0, step); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_pbs(tr, i+1, chan, dir>0, step); } if (!dir) { is_bidirectional = 1; release_first_stroke = find_pbs(tr, k, chan, 1, step); - if (is_anyshift) { - alt_release_stroke = find_pbs(tr, 0, chan, 1, step); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_release_stroke[i] = find_pbs(tr, i+1, chan, 1, step); } } } else if (mod) { // pb mod first_stroke = find_pb(tr, k, chan, 0, mod, step, n_steps, steps); - if (is_anyshift) { - alt_press_stroke = find_pb(tr, 0, chan, 0, mod, - step, n_steps, steps); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_pb(tr, i+1, chan, 0, mod, + step, n_steps, steps); } } else { // pb on/off first_stroke = find_pb(tr, k, chan, 0, 0, 0, 0, 0); release_first_stroke = find_pb(tr, k, chan, 1, 0, 0, 0, 0); - if (is_anyshift) { - alt_press_stroke = find_pb(tr, 0, chan, 0, 0, 0, 0, 0); - alt_release_stroke = find_pb(tr, 0, chan, 1, 0, 0, 0, 0); + if (is_anyshift) for (int i = 0; i < N_SHIFTS; i++) { + alt_press_stroke[i] = find_pb(tr, i+1, chan, 0, 0, 0, 0, 0); + alt_release_stroke[i] = find_pb(tr, i+1, chan, 1, 0, 0, 0, 0); } is_keystroke = 1; } @@ -1504,13 +1528,11 @@ start_translation(translation *tr, char *which_key) fprintf(stderr, "syntax error: [%s]%s\n", current_translation, which_key); return 1; } - if ((!first_stroke || *first_stroke) || - (is_bidirectional && - (!release_first_stroke || *release_first_stroke)) || + if (chk(first_stroke) || + (is_bidirectional && chk(release_first_stroke)) || (is_anyshift && - ((!alt_press_stroke || *alt_press_stroke) || - (is_bidirectional && - (!alt_release_stroke || *alt_release_stroke))))) { + (chks(alt_press_stroke) || + (is_bidirectional && chks(alt_release_stroke))))) { fprintf(stderr, "already defined: [%s]%s\n", current_translation, which_key); return 1; } @@ -1585,7 +1607,7 @@ add_release(int all_keys) if (s->keysym) { append_stroke(s->keysym, s->press); } else if (s->shift) { - append_shift(); + append_shift(s->shift); } else if (!s->status) { append_nop(); } else { @@ -1598,30 +1620,14 @@ add_release(int all_keys) } if (all_keys && is_anyshift) { // create a duplicate for any-shift translations (?) - stroke *s = *press_first_stroke; - first_stroke = alt_press_stroke; - while (s) { - if (s->keysym) { - append_stroke(s->keysym, s->press); - } else if (s->shift) { - append_shift(); - } else if (!s->status) { - append_nop(); - } else { - append_midi(s->status, s->data, - s->step, s->n_steps, s->steps, - s->swap, s->incr, s->recursive); - } - s = s->next; - } - if (is_keystroke || is_bidirectional) { - s = *release_first_stroke; - first_stroke = alt_release_stroke; + for (int i = 0; i < N_SHIFTS; i++) { + stroke *s = *press_first_stroke; + first_stroke = alt_press_stroke[i]; while (s) { if (s->keysym) { append_stroke(s->keysym, s->press); } else if (s->shift) { - append_shift(); + append_shift(s->shift); } else if (!s->status) { append_nop(); } else { @@ -1632,6 +1638,26 @@ add_release(int all_keys) s = s->next; } } + if (is_keystroke || is_bidirectional) { + for (int i = 0; i < N_SHIFTS; i++) { + stroke *s = *release_first_stroke; + first_stroke = alt_release_stroke[i]; + while (s) { + if (s->keysym) { + append_stroke(s->keysym, s->press); + } else if (s->shift) { + append_shift(s->shift); + } else if (!s->status) { + append_nop(); + } else { + append_midi(s->status, s->data, + s->step, s->n_steps, s->steps, + s->swap, s->incr, s->recursive); + } + s = s->next; + } + } + } } } @@ -1898,9 +1924,14 @@ read_config_file(void) case '\0': // no newline at eof if (!strcmp(tok, "RELEASE")) add_keystroke(tok, PRESS_RELEASE); - else if (!strcmp(tok, "SHIFT")) - append_shift(); - else if (!strcmp(tok, "NOP")) + else if (!strncmp(tok, "SHIFT", 5)) { + int shift = isdigit(tok[5])?tok[5]-'0':1; + if ((tok[5] == 0 || (isdigit(tok[5]) && tok[6] == 0)) && + shift >= 1 && shift <= N_SHIFTS) + append_shift(shift); + else + fprintf(stderr, "invalid shift key: [%s]%s\n", name, tok); + } else if (!strcmp(tok, "NOP")) append_nop(); else if (strncmp(tok, "XK", 2)) add_midi(tok);