Mirror with some correction
Dependencies: mbed FastIO FastPWM USBDevice
Diff: main.cpp
- Revision:
- 66:2e3583fbd2f4
- Parent:
- 65:739875521aae
- Child:
- 67:c39e66c4e000
--- a/main.cpp Wed Nov 23 19:49:20 2016 +0000 +++ b/main.cpp Sun Nov 27 06:37:47 2016 +0000 @@ -1598,6 +1598,18 @@ int8_t nButtons; // number of live button slots allocated int8_t zblButtonIndex = -1; // index of ZB Launch button slot; -1 if unused +// Shift button state +struct +{ + int8_t index; // buttonState[] index of shift button; -1 if none + uint8_t state : 2; // current shift state: + // 0 = not shifted + // 1 = shift button down, no key pressed yet + // 2 = shift button down, key pressed + uint8_t pulse : 1; // sending pulsed keystroke on release + uint32_t pulseTime; // time of start of pulsed keystroke +} +__attribute__((packed)) shiftButton; // Button data uint32_t jsButtons = 0; @@ -1678,6 +1690,9 @@ // presume we'll find no keyboard keys kbKeys = false; + // presume no shift key + shiftButton.index = -1; + // Count up how many button slots we'll need to allocate. Start // with assigned buttons from the configuration, noting that we // only need to create slots for buttons that are actually wired. @@ -1720,6 +1735,13 @@ if (cfg.button[i].flags & BtnFlagPulse) bs->pulseState = 1; + // If this is the shift button, note its buttonState[] index. + // We have to figure the buttonState[] index separately from + // the config index, because the indices can differ if some + // config slots are left unused. + if (cfg.shiftButton == i+1) + shiftButton.index = bs - buttonState; + // advance to the next button ++bs; } @@ -1734,14 +1756,15 @@ if (cfg.plunger.zbLaunchBall.port != 0) { // Point back to the config slot for the keyboard data. - // We use a special extra slot for virtual buttons, so - // we also need to set up the slot data. + // We use a special extra slot for virtual buttons, + // so we also need to set up the slot data by copying + // the ZBL config data to our virtual button slot. bs->cfgIndex = ZBL_BUTTON_CFG; cfg.button[ZBL_BUTTON_CFG].pin = PINNAME_TO_WIRE(NC); cfg.button[ZBL_BUTTON_CFG].typ = cfg.plunger.zbLaunchBall.keytype; cfg.button[ZBL_BUTTON_CFG].val = cfg.plunger.zbLaunchBall.keycode; - // advnace to the next button + // advance to the next button ++bs; } @@ -1772,13 +1795,74 @@ // calculate the time since the last run uint32_t dt = buttonTimer.read_us(); buttonTimer.reset(); + + // check the shift button state + if (shiftButton.index != -1) + { + ButtonState *sbs = &buttonState[shiftButton.index]; + switch (shiftButton.state) + { + case 0: + // Not shifted. Check if the button is now down: if so, + // switch to state 1 (shift button down, no key pressed yet). + if (sbs->physState) + shiftButton.state = 1; + break; + + case 1: + // Shift button down, no key pressed yet. If the button is + // now up, it counts as an ordinary button press instead of + // a shift button press, since the shift function was never + // used. Return to unshifted state and start a timed key + // pulse event. + if (!sbs->physState) + { + shiftButton.state = 0; + shiftButton.pulse = 1; + shiftButton.pulseTime = 50000+dt; // 50 ms left on the key pulse + } + break; + + case 2: + // Shift button down, other key was pressed. If the button is + // now up, simply clear the shift state without sending a key + // press for the shift button itself to the PC. The shift + // function was used, so its ordinary key press function is + // suppressed. + if (!sbs->physState) + shiftButton.state = 0; + break; + } + } // scan the button list ButtonState *bs = buttonState; for (int i = 0 ; i < nButtons ; ++i, ++bs) { - // if it's a pulse-mode switch, get the virtual pressed state - if (bs->pulseState != 0) + // Check the button type: + // - shift button + // - pulsed button + // - regular button + if (shiftButton.index == i) + { + // This is the shift button. Its logical state for key + // reporting purposes is controlled by the shift buttton + // pulse timer. If we're in a pulse, its logical state + // is pressed. + if (shiftButton.pulse) + { + // deduct the current interval from the pulse time, ending + // the pulse if the time has expired + if (shiftButton.pulseTime > dt) + shiftButton.pulseTime -= dt; + else + shiftButton.pulse = 0; + } + + // the button is logically pressed if we're in a pulse + bs->logState = shiftButton.pulse; + } + else if (bs->pulseState != 0) { // if the timer has expired, check for state changes if (bs->pulseTime > dt) @@ -1855,10 +1939,30 @@ } else { - // momentary switch - toggle the night mode state when the + // Momentary switch - toggle the night mode state when the // physical button is pushed (i.e., when its logical state - // transitions from OFF to ON) - if (bs->logState) + // transitions from OFF to ON). + // + // In momentary mode, night mode flag 0x02 makes it the + // shifted version of the button. In this case, only + // proceed if the shift button is pressed. + bool pressed = bs->logState; + if ((cfg.nightMode.flags & 0x02) != 0) + { + // if the shift button is pressed but hasn't been used + // as a shift yet, mark it as used, so that it doesn't + // also generate its own key code on release + if (shiftButton.state == 1) + shiftButton.state = 2; + + // if the shift button isn't even pressed + if (shiftButton.state == 0) + pressed = false; + } + + // if it's pressed (even after considering the shift mode), + // toggle night mode + if (pressed) toggleNightMode(); } } @@ -1871,10 +1975,31 @@ // key state list if (bs->logState || bs->virtState) { - // OR in the joystick button bit, mod key bits, and media key bits + // Get the key type and code. If the shift button is down AND + // this button has a shifted key meaning, use the shifted key + // meaning. Otherwise use the primary key meaning. ButtonCfg *bc = &cfg.button[bs->cfgIndex]; - uint8_t val = bc->val; - switch (bc->typ) + uint8_t typ, val; + if (shiftButton.state && bc->typ2 != BtnTypeNone) + { + // shifted - use the secondary key code + typ = bc->typ2, val = bc->val2; + + // If the shift button hasn't been used a a shift yet + // (state 1), mark it as used (state 2). This prevents + // it from generating its own keystroke when released, + // which it does if no other keys are pressed while it's + // being held. + if (shiftButton.state == 1) + shiftButton.state = 2; + } + else + { + // not shifted - use the primary key code + typ = bc->typ, val = bc->val; + } + + switch (typ) { case BtnTypeJoystick: // joystick button