Интерфейс USB клавиатуры для MSX

페이지 1/3
| 2 | 3

By АIеks

Champion (342)

АIеks의 아바타

07-03-2019, 13:54

Все больше назревает необходимость сделать возможность подключать современную USB клавиатуру к MSX. Вот опять столкнулся с трабрами в программе MGSEL. Программка вычитывает коды кнопок видимо напрямую в раскладке International (или …). И как результат мимо, на существующем решении ps/2.

Создам тему. Пусть будет для самомотивации. Наработки от меня тут проскакивали. Слово не воробей, … Smile

Login or 등록 to post comments

By Alexey

Guardian (2117)

Alexey의 아바타

07-03-2019, 14:55

Надо ещё иметь в виду, что сканкоды клавы не обязательно совпадают с выводимыми символами на MSX. Например на наших "русских" Ямахах, а также на корейцах и арабах всё совсем не так, как на MSX с qwerty клавами. Поэтому постоянно вижу грабли в программах, которые работают по сканкодам. Например у Некстора цифровая клавиатура работает со сдвигом влево на русских машинках. Некоторые программы опознают комбинации клавиш исходя из qwerty раскладки, не имеющей ничего общего с нашей ямаховской за исключением буквы 'C'. Я ведь ещё есть и японская раскладка, и вроде даже два варианта.

By АIеks

Champion (342)

АIеks의 아바타

07-03-2019, 15:53

Ага, все так.

Мне чем не устраивают существующие решения – они закрыты. Потом сложно это программить, даже риск на овер МГц процы не успевают одекватно реагировать на меняющуюся ситуацию с кнопочками.

В середине 90-х я мечтал о микрухе, которая будет замыкать контакты в матрице для Орион-128. Микруху придумали, а я вот выпал из темы. Надо догонять Smile

By АIеks

Champion (342)

АIеks의 아바타

15-03-2019, 19:16

Сегодня на стенде разобрался, где перехватывается в библиотеке USB Host Shield Library 2.0 обработка управлением светодиодами клавиатуры. Отучил библиотеку рулить светодиодами. Уже хорошо. Чуть позже надо будет понять, как сделать управление светодиодами от сигналов с MSX.

By Alexey

Guardian (2117)

Alexey의 아바타

16-03-2019, 12:44

Собственно нужен только CAPS, который можно повесить на CapsLock + его светодиод. Переключалку русского/японского можно повесить на ScrollLock и его светодиод и дополнительно на удобную комбинацию клавиш по выбору или вообще на правый Alt или Ctrl.

Правую цифровую клавиатуру надо как-то совместить с такими же цифровыми клавиатурами на разных машинках (Panasonic, Yamaha 805, и т.д.). На обычных машинках можно её отмапить на стандартные клавиши. NumLock стоит всегда держать включённым и попытки его отключить надо игнорировать.

Home, Ins, Del отмапливаем напрямую. А вот что делать с Select и Stop? Stop можно повесить на Pause/Break. Для Select тогда остаётся PrintScreen. Использовать PgUp и PgDown вообще нецелесообразно ИМХО.

By АIеks

Champion (342)

АIеks의 아바타

16-03-2019, 16:35

Разобрался, как напрямую рулить светодиодами клавиатуры. Правда, вот вышел какой то костыль. Вся проблема в том, что инициатором любых событий является клавиатура. И в оригинале управление светодиодами выполняется после парсинга соответствующих кнопок. В нашем случае эти светодиоды зажигаются из вне.

Вот что вышло. Клавиатура мигает двумя светодиодами. Как это сделать, более элегантно пока не понял. Изучать (разбираться) С++ в Arduino IDE не лучший вариант Smile

#include 
#include 

// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include 
#endif
#include 

class KbdRptParser : public KeyboardReportParser
{
    void PrintKey(uint8_t mod, uint8_t key);

  public:  
    void setLeds(USBHID* hid);

  protected:
    uint8_t HandleLockingKeys(USBHID *hid, uint8_t key);
  
    void OnControlKeysChanged(uint8_t before, uint8_t after);

    void OnKeyDown	(uint8_t mod, uint8_t key);
    void OnKeyUp	(uint8_t mod, uint8_t key);
    void OnKeyPressed(uint8_t key);
};

uint8_t KbdRptParser::HandleLockingKeys(USBHID *hid, uint8_t key) {
  uint8_t old_keys = kbdLockingKeys.bLeds;

  switch (key) {
    case UHS_HID_BOOT_KEY_NUM_LOCK:
      Serial.println(F("Num lock"));
      kbdLockingKeys.kbdLeds.bmNumLock = ~kbdLockingKeys.kbdLeds.bmNumLock;
      break;
    case UHS_HID_BOOT_KEY_CAPS_LOCK:
      Serial.println(F("Caps lock"));
      kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
      break;
    case UHS_HID_BOOT_KEY_SCROLL_LOCK:
      Serial.println(F("Scroll lock"));
      kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
      break;
  }

  //if(old_keys != kbdLockingKeys.bLeds && hid) {
  //  uint8_t lockLeds = kbdLockingKeys.bLeds;
  //  return (hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &lockLeds));
  //}

  return 0;
};


void KbdRptParser::setLeds(USBHID* hid)
{
  //kbdLockingKeys.kbdLeds.bmCapsLock = 0;   /*on*/
  //kbdLockingKeys.kbdLeds.bmScrollLock = 1; /*off*/

  kbdLockingKeys.kbdLeds.bmCapsLock = ~kbdLockingKeys.kbdLeds.bmCapsLock;
  kbdLockingKeys.kbdLeds.bmScrollLock = ~kbdLockingKeys.kbdLeds.bmScrollLock;
  
  uint8_t lockLeds = kbdLockingKeys.bLeds;
  hid->SetReport(0, 0/*hid->GetIface()*/, 2, 0, 1, &lockLeds);
}

void KbdRptParser::PrintKey(uint8_t m, uint8_t key)
{
  MODIFIERKEYS mod;
  *((uint8_t*)&mod) = m;
  Serial.print((mod.bmLeftCtrl   == 1) ? "C" : " ");
  Serial.print((mod.bmLeftShift  == 1) ? "S" : " ");
  Serial.print((mod.bmLeftAlt    == 1) ? "A" : " ");
  Serial.print((mod.bmLeftGUI    == 1) ? "G" : " ");

  Serial.print(" >");
  PrintHex(key, 0x80);
  Serial.print("< ");

  Serial.print((mod.bmRightCtrl   == 1) ? "C" : " ");
  Serial.print((mod.bmRightShift  == 1) ? "S" : " ");
  Serial.print((mod.bmRightAlt    == 1) ? "A" : " ");
  Serial.println((mod.bmRightGUI    == 1) ? "G" : " ");
};

void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)
{
  Serial.print("DN ");
  PrintKey(mod, key);
  uint8_t c = OemToAscii(mod, key);

  if (c)
    OnKeyPressed(c);
}

void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {

  MODIFIERKEYS beforeMod;
  *((uint8_t*)&beforeMod) = before;

  MODIFIERKEYS afterMod;
  *((uint8_t*)&afterMod) = after;

  if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) {
    Serial.println("LeftCtrl changed");
  }
  if (beforeMod.bmLeftShift != afterMod.bmLeftShift) {
    Serial.println("LeftShift changed");
  }
  if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) {
    Serial.println("LeftAlt changed");
  }
  if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) {
    Serial.println("LeftGUI changed");
  }

  if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) {
    Serial.println("RightCtrl changed");
  }
  if (beforeMod.bmRightShift != afterMod.bmRightShift) {
    Serial.println("RightShift changed");
  }
  if (beforeMod.bmRightAlt != afterMod.bmRightAlt) {
    Serial.println("RightAlt changed");
  }
  if (beforeMod.bmRightGUI != afterMod.bmRightGUI) {
    Serial.println("RightGUI changed");
  }

}

void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key)
{
  Serial.print("UP ");
  PrintKey(mod, key);
}

void KbdRptParser::OnKeyPressed(uint8_t key)
{
  Serial.print("ASCII: ");
  Serial.println((char)key);
};

USB     Usb;
//USBHub     Hub(&Usb);
HIDBoot    HidKeyboard(&Usb);

KbdRptParser Prs;

void setup()
{
  Serial.begin( 115200 );
#if !defined(__MIPSEL__)
  while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
  Serial.println("Start");

  if (Usb.Init() == -1)
    Serial.println("OSC did not start.");

  delay( 200 );

  HidKeyboard.SetReportParser(0, &Prs);
}

void loop()
{
  Usb.Task();
  delay(200);
  Prs.setLeds(&HidKeyboard);
}

Еще заметил, что инициализируется клавиатура после подачи питания достаточно долго (около 6 секунд). 3 секунды мигает синий светодиод на платке микроконтроллера и 3 секунды проходит до парсинга кнопок в консоли (отладочный монитор).

Почему-то форум скушал после #include буковки.

By АIеks

Champion (342)

АIеks의 아바타

16-03-2019, 16:17

Alexey, на мой взгляд как замапить кнопки это дело вкуса. А еще сейчас такой выбор клавиатур, что универсально точно не выйдет. У меня в данный момент такая - Golden Field K111S Black.

Одно пока очевидно. Надо иметь две раскладки интернациональную и региональную.

By Alexey

Guardian (2117)

Alexey의 아바타

16-03-2019, 16:40

Двумя не обойдётесь. Smile Минимум 2 стандартных латинских. Это ещё не берём в рассчёт немецкую и французскую, у которых латинские кнопки перепутаны. А ещё есть в этой раскладке символы с чёрточками, точками и прочей ерундой. В региональных есть не только русская, а ещё японская, корейская и арабская. На последние две можно забить.

By АIеks

Champion (342)

АIеks의 아바타

16-03-2019, 19:09

Подключил старую Logitech клавиатуру. Светодиоды не моргают. Подумал может я чего напортачил. Загрузил дефолтный пример. Та же фигня. Вон оно как. Все остальное работает исправно, только у меня сложилось мнение, что клавиатура, что ли тормознутая.

Вот этот костыль delay(200) уже критичен. Начинает пропускать быстрое нажатие кнопок.

void loop()
{
  Usb.Task();
  delay(200);
  Prs.setLeds(&HidKeyboard);
}

И еще при подключении по горячему не всегда заводиться. Может напряжение просаживается, стенд у меня на соплях сделан в данный момент.

Alexey wrote:

Двумя не обойдётесь. Smile Минимум 2 стандартных латинских. Это ещё не берём в рассчёт ...

Я, почему-то, думал, что интернациональная раскладка одна. Все остальные у меня региональные. Опираясь на эту инфу

;	KEYTYP	keyboard layout
;		0 = Japanese 
;		1 = International (QWERTY/other) 
;		2 = French (AZERTY) 
;		3 = English 
;		4 = German (DIN)
;		5 = USSR
;		6 = Spanish
;		7 = Swedish ??
;	BASVER	0 = Japanese
;		1 = International

Хотя раскладок конечно больше.

P.S. Еще интересное наблюдение. При горячем подключении клавиатуры. Селф тесты клавиатуры не выполняют.

By АIеks

Champion (342)

АIеks의 아바타

17-03-2019, 01:35

Убрал костыли. Добавил диагностические сообщения. По готовности клавиатура моргнет светодиодами. Сообщение Set report error: 0 и есть момент подмигивания светодиодами.

Start
not Ready
not Ready
not Ready
not Ready
not Ready
not Ready
not Ready
not Ready
not Ready
not Ready
not Ready
not Ready
Set report error: 0
Set report error: 0
DN      >22<     
ASCII: 5
UP      >22<     
DN      >22<     
ASCII: 5

Ну не так быстр видимо для этой задачи 8MГц проц. По готовности уже бегает быстро, но до этого… Как есть. 3сек до готовности после сброса проца oO

By АIеks

Champion (342)

АIеks의 아바타

25-03-2019, 11:54

Эх, опять связался с МГТФ. Да красиво, эстетично, но очень, очень долго Sad Ну, ничего доделаю в следующем месяце макетку, а потом софт.

페이지 1/3
| 2 | 3