Allow up to four different internal shift keys.

master
Albert Graef 2018-09-12 19:57:03 +02:00
parent 5baa93cb91
commit fd883c1391
4 changed files with 203 additions and 159 deletions

View File

@ -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

View File

@ -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)
;

View File

@ -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);

View File

@ -427,7 +427,7 @@ finish_translation_section(translation *tr)
int k;
if (tr) {
for (k=0; k<2; k++) {
for (k=0; k<N_SHIFTS+1; k++) {
finish_stroke_data(&tr->pc[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; k<N_SHIFTS+1; k++) {
free_stroke_data(tr->pc[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);