JoyStick Shield V1.a库编写+封装

昨天给L同学展示了一下这个遥控器,今天为它封装一个库吧

上面的接口可以加诺基亚的屏幕或者与外界沟通的器件


(A)1个PS2带按钮十字摇杆,4颗圆形按钮,2个小按键。

(B)板载的开关电压可以在3.3V和5V之间切换。

(C)1个复位按键

(D)xbee/Bluetooh Bee/APC220蓝牙无线数传接口

(E)2.4G NRF24L01 RF无线数传接口

(F)Nokia 5110 LCD接口


其中对于摇杆来说,摇杆有两个电位器,可连接到Arduino上的模拟引脚A0和A1。A0的值对应于X位置。A1的值对应于Y位置。要读取这些模拟值,请使用AnalogRead()函数。

在这里

找到了一些对应的引脚映射图

https://cdn.sparkfun.com/datasheets/Dev/Arduino/Shields/Joystick_Shield-v14.pdf

包括一个原理图,其实用万用表就可以测出来


接下来就给我们的板子写个驱动吧!在写之前,先写一个关于摇杆的代码~


我们先把引脚安排了

两个数字口,检测XY

SW检测是否摁下


#define x A5 //定义X轴对应的引脚为A5 #define y A4 //定义y轴对应的引脚为A4#define sw 2 //定义按键对应的引脚为2 void setup() { pinMode(sw, INPUT); //设置为输入模式 digitalWrite(sw,HIGH); //给sw高电平,非按下状态为1,按下状态为0 Serial.begin(115200); //设置波特率} void loop() { Serial.print("x = "); //串口输出x值 Serial.print(analogRead(x)); Serial.print(" | "); Serial.print("y = "); //串口输出y值 Serial.print(analogRead(y)); Serial.print(" | "); Serial.print("key = "); //串口输出sw值 Serial.println(digitalRead(sw)); delay(50); //延时50毫秒}

结果,中间加 | 好看

库的组织形式是这样的

例子+实现的头+源码+关键词+reademe+授权

#ifndef JoystickShield_H#define JoystickShield_H
#define CENTERTOLERANCE 5
// 兼容 Arduino 1.0
#if ARDUINO >= 100#include <Arduino.h>#else#include <WProgram.h>#endif

先写点头,其实有时候不知道先写头是身子

/** * 枚举来保存操纵杆的不同状态 * */enum JoystickStates{ CENTER, // 0 UP, RIGHT_UP, RIGHT, RIGHT_DOWN, DOWN, LEFT_DOWN, LEFT, LEFT_UP //8};

用枚举来保存状态

头文件的组织形式

我们要编写的子函数是这么多

涉及到的回调和一些变量

static const bool ALL_BUTTONS_OFF[7] = {false, false, false, false, false, false, false};//将按钮状态数组初始化为所有未按下的按钮

管理一些板子上面按钮的初始情况

public: JoystickShield(); // 构造函数
void setJoystickPins(byte pinX, byte pinY); void setButtonPins(byte pinSelect, byte pinUp, byte pinRight, byte pinDown, byte pinLeft, byte pinF, byte pinE void setButtonPinsUnpressedState(byte pinSelect, byte pinUp, byte pinRight, byte pinDown, byte pinLeft, byte p void setThreshold(int xLow, int xHigh, int yLow, int yHigh);
void processEvents(); void processCallbacks();
void calibrateJoystick();
// 摇杆的事件 bool isCenter(); bool isUp(); bool isRightUp(); bool isRight(); bool isRightDown(); bool isDown(); bool isLeftDown(); bool isLeft(); bool isLeftUp(); bool isNotCenter();
// 摇杆坐标 int xAmplitude(); int yAmplitude();
// Button events bool isJoystickButton(); bool isUpButton(); bool isRightButton(); bool isDownButton(); bool isLeftButton(); bool isFButton(); bool isEButton();
// 摇杆回调 void onJSCenter(void (*centerCallback)(void)); void onJSUp(void (*upCallback)(void)); void onJSRightUp(void (*rightUpCallback)(void)); void onJSRight(void (*rightCallback)(void)); void onJSRightDown(void (*rightDownCallback)(void)); void onJSDown(void (*downCallback)(void)); void onJSLeftDown(void (*leftDownCallback)(void)); void onJSLeft(void (*leftCallback)(void)); void onJSLeftUp(void (*leftUpCallback)(void)); void onJSnotCenter(void (*notCenterCallback)(void));
// 按钮回调 void onJoystickButton(void (*jsButtonCallback)(void)); void onUpButton(void (*upButtonCallback)(void)); void onRightButton(void (*rightButtonCallback)(void)); void onDownButton(void (*downButtonCallback)(void)); void onLeftButton(void (*leftButtonCallback)(void)); void onFButton(void (*FButtonCallback)(void)); void onEButton(void (*EButtonCallback)(void));

这些函数统一是共有的,用public修饰一下

具体的作用和参数后面实现的时候再讲

// 阈值 int x_threshold_low; int x_threshold_high; int y_threshold_low; int y_threshold_high; // 操纵杆的引脚 byte pin_analog_x; byte pin_analog_y; // 按钮摇杆 byte pin_joystick_button; byte pin_up_button; byte pin_right_button; byte pin_down_button; byte pin_left_button; byte pin_F_button; byte pin_E_button; byte pin_joystick_button_unpressed; byte pin_up_button_unpressed; byte pin_right_button_unpressed; byte pin_down_button_unpressed; byte pin_left_button_unpressed; byte pin_F_button_unpressed; byte pin_E_button_unpressed; // 摇杆 byte joystickStroke; int x_position; int y_position; //当前的摇杆状态 JoystickStates currentStatus; // 按钮状态数组,允许同时按下多个按钮 //顺序是上、右、下、左、e、f、操纵杆 bool buttonStates[7];

使用到的变量用private修饰

// 摇杆回调void (*centerCallback)(void);void (*upCallback)(void);void (*rightUpCallback)(void);void (*rightCallback)(void);void (*rightDownCallback)(void);void (*downCallback)(void);void (*leftDownCallback)(void);void (*leftCallback)(void);void (*leftUpCallback)(void);void (*notCenterCallback)(void);// 按钮回调void (*jsButtonCallback)(void);void (*upButtonCallback)(void);void (*rightButtonCallback)(void);void (*downButtonCallback)(void);void (*leftButtonCallback)(void);void (*FButtonCallback)(void);void (*EButtonCallback)(void);// 辅助函数void clearButtonStates();void initializeCallbacks();

所有的回调函数,同理

下面开始写实现,一开始嘛~写个构造函数不为过,走你!

/** * 构造函数 * */JoystickShield::JoystickShield(){ // 定义一些阈值。如果你的操纵杆不同,改这里 setThreshold(510, 530, 510, 540);
// 摇杆将操纵杆连接到引脚 0 和 1。自己也是可以去更改的 setJoystickPins(0, 1);
// 扩展板的按钮引脚 setButtonPins(8, 2, 3, 4, 5, 7, 6);
// 默认情况下的居中的位置 currentStatus = CENTER;
// 将按钮状态数组初始化为所有未按下的按钮 memcpy(buttonStates, ALL_BUTTONS_OFF, sizeof(ALL_BUTTONS_OFF));
// 将所有回调函数指针初始化为 NULL initializeCallbacks();}

上面的一些函数是子函数,接下来慢慢实现

/** * 设置连接到操纵杆的Analyog引脚 * */void JoystickShield::setJoystickPins(byte pinX, byte pinY){ pin_analog_x = pinX; pin_analog_y = pinY;
// 将操纵杆引脚设置为输入模式 pinMode(pin_analog_x, INPUT); pinMode(pin_analog_y, INPUT);}

就是XY的电位器引脚的设置,函数是自带的

在头文件按内部有定义

/** * 设置按钮使用的引脚 * 要停用按钮,请使用 arduino 范围之外的引脚,例如 255 */void JoystickShield::setButtonPins(byte pinSelect, byte pinUp, byte pinRight, byte pinDown, byte pinLeft, byte pinF, byte pinE){ pin_joystick_button = pinSelect;
pin_up_button = pinUp; pin_right_button = pinRight; pin_down_button = pinDown; pin_left_button = pinLeft;
pin_F_button = pinF; pin_E_button = pinE;
//将按钮引脚设置为输入模式 pinMode(pin_joystick_button, INPUT); pinMode(pin_up_button, INPUT); pinMode(pin_right_button, INPUT); pinMode(pin_down_button, INPUT); pinMode(pin_left_button, INPUT); pinMode(pin_E_button, INPUT); pinMode(pin_F_button, INPUT);
//按钮默认使用上拉电阻 setButtonPinsUnpressedState(HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH);}

对这些按钮进行设置,在上面得调用里面也是有的

/* * * 配置来自未按下按钮的输入是高还是低。 * 这将相应地为按钮的引脚启用上拉或下拉电阻。 */void JoystickShield::setButtonPinsUnpressedState(byte pinSelect, byte pinUp, byte pinRight, byte pinDown, byte pinLeft, byte pinF, byte pinE){ //存储未按下状态 pin_joystick_button_unpressed = pinSelect ? HIGH : LOW; pin_up_button_unpressed = pinUp ? HIGH : LOW; pin_right_button_unpressed = pinRight ? HIGH : LOW; pin_down_button_unpressed = pinDown ? HIGH : LOW; pin_left_button_unpressed = pinLeft ? HIGH : LOW; pin_F_button_unpressed = pinF ? HIGH : LOW; pin_E_button_unpressed = pinE ? HIGH : LOW;
//为按钮启用上拉或下拉电阻 digitalWrite(pin_joystick_button, pin_joystick_button_unpressed); digitalWrite(pin_up_button, pin_up_button_unpressed); digitalWrite(pin_right_button, pin_right_button_unpressed); digitalWrite(pin_down_button, pin_down_button_unpressed); digitalWrite(pin_left_button, pin_left_button_unpressed); digitalWrite(pin_F_button, pin_F_button_unpressed); digitalWrite(pin_E_button, pin_E_button_unpressed);}

按钮按下后的传感器情况,一次7个按钮,单独管理很呆,写个函数就好了

/** * 为操纵杆配置阈值 */void JoystickShield::setThreshold(int xLow, int xHigh, int yLow, int yHigh){ x_threshold_low = xLow; x_threshold_high = xHigh; y_threshold_low = yLow; y_threshold_high = yHigh;

XY的阈值时多少,也要约束

太那啥了,模糊.懂就行


/** * *校准操纵杆 * */void JoystickShield::calibrateJoystick(){ byte i;
// 校准 x int xCenter = 0; for (i = 0; i < 10; i++) xCenter += analogRead(pin_analog_x); xCenter /= i;
// 校准 y int yCenter = 0; for (i = 0; i < 10; i++) yCenter += analogRead(pin_analog_y); yCenter /= i;
// 保存摇杆行程 joystickStroke = max(pin_analog_x, pin_analog_y) * 1.01;
// 设置中心差 setThreshold(xCenter - CENTERTOLERANCE, xCenter + CENTERTOLERANCE, yCenter - CENTERTOLERANCE, yCenter + CENTERTOLERANCE);}

作为我们的遥控器,怎么能少的了校准功能呢

整一个!

精华代码,想法就是先假定我们已经知道中心位置了

然后去加减实际的数值,获得一个修正的校准值

/** * 处理的函数,在loop()中不停轮回,它们真累 * */void JoystickShield::processEvents(){ int x_direction = 0; int y_direction = 0;
// 从操纵杆引脚读取 x_position = analogRead(pin_analog_x); y_position = analogRead(pin_analog_y);
// 确定操纵杆方向 if (x_position > x_threshold_high) { x_direction = 1; x_position = map(x_position, x_threshold_high, x_threshold_high + x_threshold_low, 0, 100); x_position = constrain(x_position, 0, 100); } else if (x_position < x_threshold_low) { x_direction = -1; x_position = map(x_position, 0, x_threshold_low, -100, 0); } else x_position = 0;
if (y_position > y_threshold_high) { y_direction = 1; y_position = map(y_position, y_threshold_high, y_threshold_high + y_threshold_low, 0, 100); y_position = constrain(y_position, 0, 100); } else if (y_position < y_threshold_low) { y_direction = -1; y_position = map(y_position, 0, y_threshold_low, -100, 0); } else y_position = 0;
if (x_direction == -1) { if (y_direction == -1) { currentStatus = LEFT_DOWN; } else if (y_direction == 0) { currentStatus = LEFT; } else { currentStatus = LEFT_UP; } } else if (x_direction == 0) { if (y_direction == -1) { currentStatus = DOWN; } else if (y_direction == 0) { currentStatus = CENTER; } else { currentStatus = UP; } } else { if (y_direction == -1) { currentStatus = RIGHT_DOWN; } else if (y_direction == 0) { currentStatus = RIGHT; } else { currentStatus = RIGHT_UP; }    }

全场最--\(˙<>˙)/--的代码来啦!

我们先认为,现在不做任何动作的时候是原点(这不废话)

然后我们去读传感器的数值

实在不好看,我再画个简图

x = map(t,fromMAX,fromMIN,toMAX,forMIN);
x,t为同类型变量formMAX与fromMIN为t变量本身的上下界toMAX与toMIN为x变量的上下界
该函数将t变量值根据范围比例变换后将结果存入x变量。

看不懂?

map(num,旧区间初值,旧区间终值,新区间初值,新区间终值);意思就是把num这个数从旧区间映射到新区间

这个看懂了吧

也用到了这个函数

对一个方向的映射和计算

对一个方向的完整版

两个方向的映射计算

这里的代码是按钮对角线的位置

大概就是这样

if (x_direction == -1) { if (y_direction == -1) { currentStatus = LEFT_DOWN;//6 } else if (y_direction == 0) { currentStatus = LEFT;//7 } else { currentStatus = LEFT_UP;//8 } } else if (x_direction == 0) { if (y_direction == -1) { currentStatus = DOWN; } else if (y_direction == 0) { currentStatus = CENTER; } else { currentStatus = UP; } } else { if (y_direction == -1) { currentStatus = RIGHT_DOWN; } else if (y_direction == 0) { currentStatus = RIGHT; } else { currentStatus = RIGHT_UP; }

通过简单的判断标志位,想不出来别的巧妙的办法了

//确定按下了哪些按钮,相应地将按钮状态数组值设置为 true/false buttonStates[0] = digitalRead(pin_up_button) != pin_up_button_unpressed; buttonStates[1] = digitalRead(pin_right_button) != pin_right_button_unpressed; buttonStates[2] = digitalRead(pin_down_button) != pin_down_button_unpressed; buttonStates[3] = digitalRead(pin_left_button) != pin_left_button_unpressed; buttonStates[4] = digitalRead(pin_E_button) != pin_E_button_unpressed; buttonStates[5] = digitalRead(pin_F_button) != pin_F_button_unpressed; buttonStates[6] = digitalRead(pin_joystick_button) != pin_joystick_button_unpressed;

来判断摁下了什么按钮,更改标志位

if (isCenter() && centerCallback != NULL) { centerCallback(); }

先展示一个回调事件

摇杆的回调就这么多

// 按钮回调if (isJoystickButton() && jsButtonCallback != NULL){ jsButtonCallback();}

和上面一样,写一个按钮回调样子

同理

/** * 处于中心状态的操纵杆 * */bool JoystickShield::isCenter(){ if (currentStatus == CENTER) { return true; } else { return false; }}
/** * * 摇杆x位置,从-100到100,0为中心 */int JoystickShield::xAmplitude(){ return x_position;}

数组读取法

/** * 摇杆按钮按下 * */bool JoystickShield::isJoystickButton(){ return buttonStates[6];}

摇杆的按钮,CW

/** * 将所有函数指针初始化为 NULL * */void JoystickShield::initializeCallbacks(){ // 操纵杆回调 centerCallback = NULL; upCallback = NULL; rightUpCallback = NULL; rightCallback = NULL; rightDownCallback = NULL; downCallback = NULL; leftDownCallback = NULL; leftCallback = NULL; leftUpCallback = NULL; notCenterCallback = NULL;
// 按钮回调 jsButtonCallback = NULL; upButtonCallback = NULL; rightButtonCallback = NULL; downButtonCallback = NULL; leftButtonCallback = NULL; FButtonCallback = NULL; EButtonCallback = NULL;}

写回调函数前,把指针的事情理明白

/** * 操纵杆回调 * *//****************************************************************** */void JoystickShield::onJSCenter(void (*centerCallback)(void)){ this->centerCallback = centerCallback;}
void JoystickShield::onJSUp(void (*upCallback)(void)){ this->upCallback = upCallback;}
void JoystickShield::onJSRightUp(void (*rightUpCallback)(void)){ this->rightUpCallback = rightUpCallback;}
void JoystickShield::onJSRight(void (*rightCallback)(void)){ this->rightCallback = rightCallback;}
void JoystickShield::onJSRightDown(void (*rightDownCallback)(void)){ this->rightDownCallback = rightDownCallback;}
void JoystickShield::onJSDown(void (*downCallback)(void)){ this->downCallback = downCallback;}
void JoystickShield::onJSLeftDown(void (*leftDownCallback)(void)){ this->leftDownCallback = leftDownCallback;}
void JoystickShield::onJSLeft(void (*leftCallback)(void)){ this->leftCallback = leftCallback;}
void JoystickShield::onJSLeftUp(void (*leftUpCallback)(void)){ this->leftUpCallback = leftUpCallback;}
void JoystickShield::onJSnotCenter(void (*notCenterCallback)(void)){ this->notCenterCallback = notCenterCallback;}

摇杆回调

/** * 按钮回调 * *//****************************************************************** */void JoystickShield::onJoystickButton(void (*jsButtonCallback)(void)){ this->jsButtonCallback = jsButtonCallback;}
void JoystickShield::onUpButton(void (*upButtonCallback)(void)){ this->upButtonCallback = upButtonCallback;}
void JoystickShield::onRightButton(void (*rightButtonCallback)(void)){ this->rightButtonCallback = rightButtonCallback;}
void JoystickShield::onDownButton(void (*downButtonCallback)(void)){ this->downButtonCallback = downButtonCallback;}
void JoystickShield::onLeftButton(void (*leftButtonCallback)(void)){ this->leftButtonCallback = leftButtonCallback;}
void JoystickShield::onFButton(void (*FButtonCallback)(void)){ this->FButtonCallback = FButtonCallback;}
void JoystickShield::onEButton(void (*EButtonCallback)(void)){ this->EButtonCallback = EButtonCallback;}

按钮回调


非静态成员函数实际上的形参个数比程序员写的多一个。

多出来的参数就是所谓的“this指针”。

这个“this指针”指向了成员函数作用的对象,在成员函数执行的过程中,正是通过“Ihis指针”才能找到对象所在的地址,因而也就能找到对象的所有非静态成员变量的地址。



this 指针是一个隐含于每一个成员函数中的特殊指针。它指向正在被该成员函数操作的那个对象。

当对一个对象调用成员函数时,编译程序先将对象的地址赋给 this 指针,然后调用成员函数,每次成员函数存取数据成员时,由隐含使用 this 指针。

当一个成员函数被调用时,自动向它传递一个隐含的参数,该参数是一个指向这个成员函数所在的对象的指针。

this 指针被隐含地声明为: ClassName const this,这意味着不能给 this 指针赋值;在 ClassName 类的 const 成员函数中,this 指针的类型为:const ClassName const,这说明不能对 this 指针所指向的这种对象是不可修改的(即不能对这种对象的数据成员进行赋值操作);

由于 this 并不是一个常规变量,所以,不能取得 this 的地址。

在以下场景中,经常需要显式引用 this 指针:

  1. 为实现对象的链式引用;

  2. 为避免对同一对象进行赋值操作;

  3. 在实现一些数据结构时,如 list。

void JoystickShield::onJSCenter(void (*centerCallback)(void))

上面这个写法是定义一个指向函数的函数指针

满足 void xxx(int, char*) 的函数

这样的形式就是回调函数

回调函数是由用户撰写,而由操作系统调用的一类函数,回调函数可以把调用者和被调用者分开,调用者(例如操作系统)不需要关心被调用者到底是哪个函数,它所知道的就是有这么一类函数,这类满足相同的函数签名(函数原型,参数,返回值等),由用户书写完毕后在被调用就可以了。实现上回调函数一般都是通过函数指针来实现的。回调函数就是一个通过函数指针调用的函数.回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。当你调用一个方法A,并不需要等待A的执行结果,而是直接往下执行,A会主动通知你,这就是回调。

https://blog.csdn.net/u014488388/article/details/54891057
http://c.biancheng.net/view/170.html

这个老哥写的demo不错

#include <JoystickShield.h>JoystickShield joystickShield; // 创建一个实例void setup(){ Serial.begin(9600);
delay(100); joystickShield.calibrateJoystick(); // 校准函数
// 摇杆回调 joystickShield.onJSUp(&up); joystickShield.onJSRightUp(&rightUp); joystickShield.onJSRight(&right); joystickShield.onJSRightDown(&rightDown); joystickShield.onJSDown(&down); joystickShield.onJSLeftDown(&leftDown); joystickShield.onJSLeft(&left); joystickShield.onJSLeftUp(&leftUp); joystickShield.onJSnotCenter(&notCenter);
// 按钮回调 joystickShield.onJoystickButton(&joystickButton); joystickShield.onUpButton(&upButton); joystickShield.onRightButton(&rightButton); joystickShield.onDownButton(&downButton); joystickShield.onLeftButton(&leftButton); joystickShield.onFButton(&FButton); joystickShield.onEButton(&EButton);}
void loop(){ joystickShield.processCallbacks(); // 你什么也没有做 delay(500);}
/** 定义回调函数 **/void up(){ Serial.println("Up from callback");}
void rightUp(){ Serial.println("Right Up from callback");}
void right(){ Serial.println("Right from callback");}
void rightDown(){ Serial.println("Right Down from callback");}
void down(){ Serial.println("Down from callback");}
void leftDown(){ Serial.println("Left Down from callback");}
void left(){ Serial.println("Left from callback");}
void leftUp(){ Serial.println("Left Up from callback");}
void joystickButton(){ Serial.println("Joystick from callback");}
void upButton(){ Serial.println("Up Button from callback");}
void rightButton(){ Serial.println("Right Button from callback");}
void downButton(){ Serial.println("Down Button from callback");}
void leftButton(){ Serial.println("Left Button from callback");}
void FButton(){ Serial.println("F Button from callback");}
void EButton(){ Serial.println("E Button from callback");}
void notCenter(){ Serial.println("回调不在中心"); // 新的位置函数 Serial.print("x "); Serial.print(joystickShield.xAmplitude()); Serial.print(" y "); Serial.println(joystickShield.yAmplitude());}

写个回调的例子

#################################################
######################################## Datatypes (KEYWORD1)#######################################
JoystickShield KEYWORD1
######################################## Methods and Functions (KEYWORD2)#######################################
setJoystickPins KEYWORD2setButtonPins KEYWORD2setThreshold KEYWORD2
processEvents KEYWORD2processCallbacks KEYWORD2

# Joystick Functions
isCenter KEYWORD2isUp KEYWORD2isRightUp KEYWORD2isRight KEYWORD2isRightDown KEYWORD2isDown KEYWORD2isLeftDown KEYWORD2isLeft KEYWORD2isLeftUp KEYWORD2isnotCenter KEYWORD2
# Button Functions
isJoystickButton KEYWORD2isUpButton KEYWORD2isRightButton KEYWORD2isDownButton KEYWORD2isLeftButton KEYWORD2isFButton KEYWORD2isEButton KEYWORD2
# Joystick coordinatesxAmplitude KEYWORD2yAmplitude KEYWORD2
# Joystick callbacks Functions
onJSCenter KEYWORD2onJSUp KEYWORD2onJSRightUp KEYWORD2onJSRight KEYWORD2onJSRightDown KEYWORD2onJSDown KEYWORD2onJSLeftDown KEYWORD2onJSLeft KEYWORD2onJSLeftUp KEYWORD2onJSnotCenter KEYWORD2
# Button callbacks
onJoystickButton KEYWORD2onUpButton KEYWORD2onRightButton KEYWORD2onDownButton KEYWORD2onLeftButton KEYWORD2onFButton KEYWORD2onEButton KEYWORD2
######################################## Constants (LITERAL1)#######################################
#Joystick states
CENTER LITERAL1UP LITERAL1RIGHT_UP LITERAL1RIGHT LITERAL1RIGHT_DOWN LITERAL1DOWN LITERAL1LEFT_DOWN LITERAL1LEFT LITERAL1LEFT_UP LITERAL1
#Button states
NO_BUTTON LITERAL1JOYSTICK_BUTTON LITERAL1UP_BUTTON LITERAL1RIGHT_BUTTON LITERAL1DOWN_BUTTON LITERAL1LEFT_BUTTON LITERAL1F_BUTTON LITERAL1E_BUTTON LITERAL1

keyword的列表也写一下

学C++去了,基础不牢,地动山摇.哭哭

(0)

相关推荐