fruit-bat / pico-zxspectrum

ZX Spectrum for Raspberry Pico Pi RP2040
475 stars 52 forks source link

Please add the ability to rename files without an external keyboard #93

Closed adamenkov closed 1 year ago

adamenkov commented 1 year ago

This would be super useful when renaming quick saves.

fruit-bat commented 1 year ago

Is pressing '2' for rename not working?

adamenkov commented 1 year ago

It is. But then when actually editing a file name all I can do with my ZX Spectrum keyboard is to move the cursor left or right and add/insert characters. I can't delete characters nor can I (this is minor I guess) cancel renaming by pressing Esc (which I don't have).

fruit-bat commented 1 year ago

OK, I will have a look through the key mappings and get back to you.

fruit-bat commented 1 year ago

Give this a go. Let me know if it works ok and I will release it properly and add some notes to the README.

Do you have a PICOZX with LCD (this is what the firmware below is for)?

ZxSpectrumPicomputerZxLcd.uf2.zip (Note that you need to unzip this file)

While on the menu...

SHIFT-Fire = ESC RELOAD = Backspace SHIFT-RELOAD = Del

Its a bit wonky as the emulator started out just supporting USB keyboards and processes key presses as HID events. This makes is awkward to deliver combinations of key+shift from the spectrum keyboard to generate the labelled symbols (e.g. on the menu SHIFT-9 will be '(' like on a UK 105 key USB keyboard).

adamenkov commented 1 year ago

It's working absolutely amazingly, thanks a lot!

Do you have a PICOZX with LCD (this is what the firmware below is for)?

Yes, I have a PICOZX with integrated LCD.

ArnoldUK commented 1 year ago

I updated PicoTextField.cpp to support more of the speccy keyboard keys with delete key correctly mapped. Here's the updated code:

PicoTextField::PicoTextField(int32_t x, int32_t y, int32_t w, int32_t maxchars) :
  PicoWin(x, y, w, 1),
  _cursor(0),
  _start(0),
  _maxchars(maxchars)
{
  onKeydown([=](uint8_t keycode, uint8_t modifiers, uint8_t ascii) {

    switch(ascii) {
      case 2: case 0x37: case 0x26: { // Home
        if (_cursor > 0) {
          _cursor = 0;
          _start = _cursor;
          repaint();
        }
        return false;
      }
      case 3: case 0x36: case 0x5E: { // End
        if (_cursor < textlen()) {
          _cursor = textlen();
          const int32_t e = (_cursor - _start) - ww() + 1;
          if (e > 0) {
            _start += e;
          }
          repaint();
        }
        return false;
      }
      case 129: case 0x35: case 0x25: { // left
        if (_cursor > 0) {
          _cursor--;
          if (_cursor < _start) {
            _start = _cursor;
          }
          repaint();
        }
        return false;
      }
      case 128: case 0x38: case 0x2A: { // right
        if (_cursor < textlen()) {
          _cursor++;
          const int32_t e = (_cursor - _start) - ww() + 1;
          if (e > 0) {
            _start += e;
          }
          repaint();
        }
        return false;
      }
      case '\r': { // return or enter
        if (_onenter) _onenter(_text.c_str());
        return true;
      }
      case 127: case 0x29: { // del
        if (_cursor < textlen()) {
          _text.erase(_cursor, 1);
          repaint();
        }
        return false;
      }
      case '\b': case 0x20: { // backspace
        if (_cursor > 0) {
          _cursor--;
          if (_cursor < _start) {
            _start = _cursor;
          }
          _text.erase(_cursor, 1);
          repaint();
        }
        return false;
      }
      default: {
        if (ascii >= 32 && ascii < 127) {
          if (textlen() < _maxchars) {
            _text.insert(_cursor, 1, ascii);
            _cursor++;
            const int32_t e = (_cursor - _start) - ww() + 1;
            if (e > 0) {
              _start += e;
            }
            repaint();
          }
          return false;
        }
        break;
      }
    };

    return true;
  });

void PicoTextField::clear() {
  _text.clear();
  _cursor = 0;
  _start = 0;
}