如何把老式键盘转换成USB键盘并且自己编程?

什么是PS/2接口

PS/2是IBM所推出的用于PC的接口,连接器共有6个孔,圆形设计,在1990~2000左右时间的台式机键盘是PS/2接口的,尽管在1996年已经出现了USB接口,但是受限于芯片成本和设计方案,当时的许多机械键盘依然采用PS/2接口。

 

因为没有识别协议和描述符,所以键盘鼠标必须插到以颜色划分的特定接口才能工作。

 

PS/2接口和现在的USB接口具有许多共性,比如实际使用的线缆数是4根,5V供电,但是在传输形式上有区别,PS/2接口是一根时钟线和一根数据线,而USB数据传输是D- D+差分线。

和USB相比较,PS/2接口数据处理难度低,频率低,兼容性好,按下按键后,键盘会拉低CLK电平,传输12bit的DATA信号,而拉低这个动作同时会让主板芯片组发生一个中断信号触发中断处理,所以理论上反应会比USB更快。

 

 

 

如何自己编程解码

 

PS/2接口的数据读取属于比较简单的,但是在编程上依然会有一定难度,PS/2接口传输的是11bit数据,第12Bit一定为0。这里的难度主要在于按键判别并通过USB传输上。

 

模块可以选择Arduino Leonardo,在成本和编程难度上有比较好的平衡,多数时候我比较支持使用低代码(简单调用就可以实现复杂功能的代码)来创作和改装。

 

使用模组和专用芯片转换成USB

 

要在内部修改成USB,首要选的就是可以使用的芯片,我购置了一些WIT122UH用来测试,它的价格只有几块钱。

 

我在设计上考虑到多数时候是用于内置,所以这一个模块只配置了最少的元件。

 

然后我还设计了一个更复杂一点的,用上了一个紫色的PS/2母口座,型号为DS1093-01-PN60

 

此外还有一个增强设计增加了16Pin的Type-C接口,另外还有一个母座,如果要从焊接难度出发,可以把Type-C接口替换成4pin的Micro-USB接口。

 

模块设计上,考虑两种可能,一种是外置设计一种是内置设计

 

如果你要简化DIY流程可以直接使用这些常见的PS/2接口转USB,将它们拆开可以很好的压缩体积。

 

 

举一反三

 

因为PS/2信号容易模拟,很简单就可以使用8Bit的MCU生成,因此,如果制作键盘,那么使用PS/2转USB信号的芯片,就能够以一个相对于使用原生USB接口的芯片来说更低的多的成本制作出一把USB接口的键盘。

 

 

用编程来解决

我是用Leonardo和Arduino IDE来实现这种操作,拥有很大的自由度,应用库是PS2KeyAdvanced   https://github.com/techpaul/PS2KeyAdvanced

 

对应的键盘是一把Cherry G84-4400,PS2接口

 

在使用上我用的是PS2KeyAdvanced库,和另一个PS2Keyboard库比较来说,这一个库可以支持点亮CAPS LOCK灯,而这个灯是需要控制器可以支持数据写入的。也就是往键盘写数据。

 

线路连接上,我把DATA连接在D2,CLK连接在D3。

 

关于各类函数的说明

keyboard.available()这一函数的作用很简单,就是在获取到数据的时候触发其他时候返回0,因此在loop中不断的去判断是否有返回值1。当然实际上数据是已经被缓冲存储的,因为一开始的时候设置了中断,中断函数中对键盘发送的数据进行处理。

 

 

按键值的查询

 

//sample以A为例:按下代码 释放代码
//一般:     41 8041
//CAPS LOCK下:    1041 9041
//SHIFT按住情况下: 4041 C041
//SHIFT按键:4106 8106

 

完整代码

 

#include "Keyboard.h"
#include <PS2KeyAdvanced.h>

//最新的,用于PS2转换到USB



//sample以A为例:按下代码 释放代码
//一般:     41 8041
//CAPS LOCK下:    1041 9041
//SHIFT按住情况下: 4041 C041
//SHIFT按键:4106 8106



/* Keyboard constants  Change to suit your Arduino
   define pins used for data and clock from keyboard */
#define DATAPIN 2
#define IRQPIN  3
#define UPPER 40
#define RELEASE_UPPER C0
#define SHIFTMODE 0x40
#define FUNCTION 0x80

uint16_t c;

PS2KeyAdvanced keyboard;


void setup( )
{
  // Configure the keyboard library
  keyboard.begin( DATAPIN, IRQPIN );
  Serial.begin( 115200 );
  Serial.println( "PS2 Advanced Key Simple Test:" );
  Keyboard.begin();
}


void loop( )
{
  if ( keyboard.available( ) )
  {
    // read the next key
    c = keyboard.read( );
    //For DEBUG
    if ( c > 0 )
    {
      //  DisValue(c);//DEBUG用的,获取c的具体值,状态符号和按键值
    }
    //ACTION
    if ((c & 0xFF) > 0) //判断获取的按键值c有没有大于0
    {
      DisValue(c);
      switch (c >> 8)
      {
        case 0x10://大写锁定下按下字母
          UpperKey(c);
          break;
        case 0x90://大写锁定下释放字母
          UpperKey_Release(c);
          break;
        case 0x40://SHIFT大写按下
          UpperKey(c);
          break;
        case 0xC0://SHIFT大写释放
          UpperKey_Release(c);
          break;
        case 0x11:
          if (c == 0x111D)
          {
            Keyboard.press(KEY_TAB);
          }
          break;
        case 0x91:
          if (c == 0x911D)
          {
            Keyboard.release(KEY_TAB);
          }
          break;

        case 0x00://一般按键按下
          standardKey(c);
        case 0x80://一般按键释放
          standardKey_Release(c);
          break;
        case 0x01://功能按键
          FuncKey(c);
          break;
        case 0x81://功能键和SHIFT键释放
          Serial.println( "FUNC RELEASE" );
          FuncKey_Release(c);

          break;
        case 0x41://SHIFT键按下

          break;
          break;
        case 0x20://CTRL Press And
          Keyboard.press(KEY_LEFT_CTRL);
          standardKey(c);
          break;
        case 0xA0://CTRL Release
          Keyboard.release(KEY_LEFT_CTRL);
          standardKey_Release(c);
          break;
        case 0x21: //CTRL
          Serial.println( "CTRL PRESS" );
          Keyboard.press(KEY_LEFT_CTRL);
          break;
        case 0x9: //LEFT-ALT
          Serial.println( "L-ALT PRESS" );
          Keyboard.press(KEY_LEFT_ALT);
          break;
        case 0x5: //RIGHT-ALT
          Serial.println( "R-ALT PRESS" );
          Keyboard.press(KEY_RIGHT_ALT);
          break;
        default:
          Serial.print( " Unknow Higher code: " );
          Serial.println( c >> 8, HEX );
      }
      // Keyboard.press(c);
    }
  }
}

///
/*
  Descript: For DEBUG

*///
void DisValue(unsigned int c)
{
  Serial.print( "Value " );
  Serial.print( c, HEX );
  Serial.print( " - Status Bits " );
  Serial.print( c >> 8, HEX );
  Serial.print( "  Code " );
  Serial.println( c & 0xFF, HEX );
}


///
/*
  Descript: abcde and so on,main key

*///
#define LEFT_WIN 0x008B//press
#define CAPELOCK 0x00FA//press
void standardKey(unsigned int c)
{
  int key = c << 8;
  Serial.print("Stand press :");
  if(remap(c)!=0)
  {
    Keyboard.press(remap(c));
    return;
  }
  if (((key >> 8) >= '@') && ((key >> 8) <= 'Z'))
  {
    Serial.write((key >> 8) + (97 - 65)); //输出小写字符
    Keyboard.press(c + ' ');
  }

  else
  {
    Serial.write((key >> 8)); //输出其他的字符
    Keyboard.press(c);
  }

  Serial.println("");


}

//return 0: not found
unsigned char remap(unsigned int c)
{
  unsigned int key = c << 8;
  unsigned char remap_char=0; 
  switch (key>>8)
  {
    case 0x3E:
    remap_char = '/';
    break;
    case 0x3B:
    remap_char = ',';
    break;
    case 0x3A:            //按键[']
    remap_char = 0x27;
    break;
    case 0x8B:
    remap_char = KEY_LEFT_GUI;
    break;
    case 0x3D:
    remap_char = '.';
    break;
    case 0xFA:
    remap_char = KEY_CAPS_LOCK;
    break;
    default:
    break;
  }
  return remap_char;
}

//CODE:0x 80??
void standardKey_Release(unsigned int c)
{
  int key = c << 8;
  Serial.print("Stand Release :");
  if(remap(c)!=0)
  {
    Keyboard.release(remap(c));
    return;
  }
  if (((key >> 8) >= 'A') && ((key >> 8) <= 'Z'))
  {
    Serial.write((key >> 8) + (97 - 65)); //输出小写字符
    Keyboard.release(c + ' ');
  }

  else
  {
    Serial.write((key >> 8)); //输出其他的字符
    Keyboard.release(c);
  }

  Serial.println("");

}
void UpperKey(unsigned int c)
{
  int key = c << 8;
  unsigned int chara;
  Serial.print("Upper press :");
  if (c == 0x403A) //["]
  {
    Keyboard.press(0x22);
    return;
  }
  if ((key >> 8) >= '0' && (key >> 8) <= '9')
  {
    switch (key >> 8)
    {
      case '0':
        chara = ')';
        break;
      case '1':
        chara = '!';
        break;
      case '2':
        chara = '@';
        break;
      case '3':
        chara = '#';
        break;
      case '4':
        chara = '$';
        break;
      case '5':
        chara = '%';
        break;
      case '6':
        chara = '^';
        break;
      case '7':
        chara = '&';
        break;
      case '8':
        chara = '*';
        break;
      case '9':
        chara = '(';
        break;
      default:

        break;
    }
    Serial.write(chara);
    Serial.println("");
    Keyboard.press(chara);
  }
  else
  {

    Serial.write(key >> 8);
    Serial.println("");
    Keyboard.press(key >> 8);
  }

}

void UpperKey_Release(unsigned int c)
{
  int key = c << 8;
  Serial.print("Upper release :");
  Serial.write(key >> 8);
  if (c == 0xC03A) //["]
  {
    Keyboard.release(0x22);
    return;
  }
  Serial.println("");
  Keyboard.releaseAll();
}
void rep(String s)
{
  Serial.print("Func press:");
  Serial.println(s);
}
void FuncKey(unsigned int c)
{
  int key = c << 8;
  switch (key >> 8)
  {case 0x1B :
      rep("ESC");

      Keyboard.press(KEY_ESC);
      break;
    case PS2_KEY_ENTER :
      rep("ENTER");

      Keyboard.press(0x28);
      break;
    case PS2_KEY_SPACE:
      rep("SPACE");
      Keyboard.press(0x20);
      break;
    case PS2_KEY_TAB :
      rep("TAB");
      Keyboard.press(KEY_TAB);
      break;
    case PS2_KEY_DELETE :
      rep("DELETE");
      Keyboard.press(KEY_DELETE);
      break;
    case PS2_KEY_INSERT :
      Keyboard.press(KEY_INSERT);
      rep("INSERT");
      break;
    case PS2_KEY_UP_ARROW :
      rep("UP");
      Keyboard.press(KEY_UP_ARROW);
      break;
    case PS2_KEY_DN_ARROW :
      Keyboard.press(KEY_DOWN_ARROW     );
      rep("DOWN");
      break;
    case PS2_KEY_L_ARROW :
      Keyboard.press(KEY_LEFT_ARROW   );
      rep("L_ARROW");
      break;
    case PS2_KEY_R_ARROW :
      Keyboard.press(KEY_RIGHT_ARROW);
      rep("R_ARROW");
      break;
    case PS2_KEY_PGDN :
      Keyboard.press(KEY_PAGE_DOWN   );

      rep("PGDN");
      break;
    case PS2_KEY_PGUP :
      Keyboard.press(KEY_PAGE_UP    );
      rep("PGUP");
      break;
    case PS2_KEY_END :
      Keyboard.press(KEY_END     );
      rep("END");
      break;
    case PS2_KEY_HOME:
      Keyboard.press(KEY_HOME  );
      rep("HOME");
      break;
    case PS2_KEY_SYSRQ :
      Keyboard.press(PS2_KEY_SYSRQ);
      rep("SYSRQ");
      break;
    case PS2_KEY_BACK:
      Keyboard.press(PS2_KEY_BACK);
      rep("BACK");
      break;
    case 0x04:
      rep("PRINT SCREEN");
      break;
    case PS2_KEY_F1 :
      rep("F1");
      Keyboard.press(KEY_F1);
      break;
    case PS2_KEY_F2 :
      rep("F2");
      Keyboard.press(KEY_F2);
      break;
    case PS2_KEY_F3 :
      rep("F3");
      Keyboard.press(KEY_F3);
      break;
    case PS2_KEY_F4 :
      rep("F4");
      Keyboard.press(KEY_F4);
      break;
    case PS2_KEY_F5 :
      rep("F5");
      Keyboard.press(KEY_F5);
      break;
    case PS2_KEY_F6 :
      rep("F6");
      Keyboard.press(KEY_F6);
      break;
    case PS2_KEY_F7 :
      rep("F7");
      Keyboard.press(KEY_F7);
      break;
    case PS2_KEY_F8 :
      rep("F8");
      Keyboard.press(KEY_F8);
      break;
    case PS2_KEY_F9 :
      rep("F9");
      Keyboard.press(KEY_F9);
      break;
    case PS2_KEY_F10 :
      rep("F10");
      Keyboard.press(KEY_F10);
      break;
    case PS2_KEY_F11 :
      rep("F11");
      Keyboard.press(KEY_F11);
      break;
    case PS2_KEY_F12 :
      rep("F12");
      Keyboard.press(KEY_F12);
      break;
    case PS2_KEY_F13 :
      rep("F13");
      break;
    case 0x1C:
      Keyboard.press(KEY_BACKSPACE);
      break;
    default:
      Serial.print("UNKNOW CODE:");
      Serial.println(c, HEX);

  }
}
void FuncKey_Release(unsigned int c)
{

  // Keyboard.release(c);
  Keyboard.releaseAll();
}
void KeyBoard_Press(unsigned int c)
{
  Keyboard.press(c);
}
void KeyBoard_Release(unsigned int c)
{
  Keyboard.release(c);
}

 

 

 

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 驱动级键盘模拟 USB,是指通过软件或驱动程序来模拟一个USB键盘设备。通常情况下,我们使用电脑时都会连接一个物理键盘来进行操作。但有时候我们可能需要在一些特殊的设备或场景下使用虚拟键盘,这时就可以通过驱动级键盘模拟USB来实现。 驱动级键盘模拟USB的原理是将软件层面上的按键输入转化为USB协议的数据,然后通过USB接口发送到设备端,从而实现键盘的输入操作。这种方式可以方便地在电脑上创建一个虚拟键盘设备,而无需实际连接一个物理键盘。通过驱动级键盘模拟USB,我们可以直接在电脑上模拟键盘操作,输入字符、控制光标移动等功能,方便实现特定场景下的键盘输入需求。 驱动级键盘模拟USB一般需要特定的驱动程序来实现。一般来说,这些驱动程序会在操作系统启动时加载,并创建一个虚拟的USB键盘设备。用户通过特定的软件或配置界面,可以对虚拟键盘进行设置和操作。这样,当用户进行按键输入时,驱动程序会将按键信息转化为USB协议的数据,并发送到设备端。 总之,驱动级键盘模拟USB是一种通过软件或驱动程序来模拟一个USB键盘设备的技术。它可以方便地在电脑上创建一个虚拟键盘设备,使用户能够进行键盘输入操作,方便实现特定场景下的需求。 ### 回答2: 驱动级键盘模拟 USB是指通过操作系统的驱动程序,将非USB键盘模拟成USB键盘的一种技术。 在计算机中,键盘是一种输入设备,而USB(Universal Serial Bus)是一种计算机外部设备连接标准。通常情况下,计算机通过USB接口键盘进行连接和通信。 然而,并非所有的键盘都具有USB接口。一些旧的键盘可能只有PS/2接口或其他类型的接口。为了让这些键盘能够与现代的计算机兼容,可以通过驱动级键盘模拟USB的技术,将它们模拟成USB键盘。 实现键盘模拟USB一般需要以下几个步骤:首先,需要通过驱动程序识别键盘的输入信号。其次,将键盘的输入信号转换成USB键盘的输入协议。然后,通过操作系统的USB驱动程序将转换后的信号发送给计算机。最后,计算机将这些信号解析为对应的键盘输入。 驱动级键盘模拟USB的优点是能够使非USB键盘与现代计算机兼容,并且不需要额外的硬件装。这在一些特定的场景下非常有用,例如使用键盘老式电脑或者在一些特殊的嵌入式系统中。 总的来说,驱动级键盘模拟USB是一种通过操作系统的驱动程序,使非USB键盘能够与USB接口兼容的技术。通过这种技术,我们可以将一些非USB键盘模拟成USB键盘,使其能够正常地连接和使用于现代计算机。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值