当前位置:网站首页>QT self-made soft keyboard is the most perfect and simple, just like its own virtual keyboard
QT self-made soft keyboard is the most perfect and simple, just like its own virtual keyboard
2022-07-28 14:10:00 【Source guest V】
One 、 Features of this self-made virtual keyboard
1. The keyboard interface remains at the top of all interfaces .
2. Clicking the keyboard button does not change the focus of the underlying text input box .
3. Complete keyboard input text information by simulating keyboard click events .
4. Including various keyboard built-in symbol input .
5. Long press the key to input the contents of the keyboard repeatedly .
6. Support win7、win10、Linux And so on .
7. Nice interface .
In short, it's the same as a real virtual keyboard , There will be no discomfort
Two 、windows Open the system's own soft keyboard
QDesktopServices::openUrl(QUrl("osk.exe", QUrl::TolerantMode));The traditional method of opening the system's own virtual keyboard is as follows , Just one line of code , But the virtual keyboard of the system is not necessarily easy to use , Some buttons are too small , Some computers may not have their own soft keyboard , Just write one .
3、 ... and 、 Keep the keyboard interface at the top 、 Do not change the focus of the underlying interface
Many homemade keyboards don't know how to keep the keyboard at the top , It is found that after clicking the keyboard interface, the system focus is on the keyboard interface , The cursor is not in the bottom row input box , After input, click OK to transfer the keyboard content to the bottom interface , It doesn't look like it nice, In fact, these two problems are very simple and can be solved , The code is as follows
this->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus);Qt::WindowStaysOnTopHint Set window top Qt::WindowDoesNotAcceptFocus Set unfocused window
Four 、 Press and hold the key to input the contents of the keyboard repeatedly
Especially when we click the backspace delete button , There are more texts. When we use a real keyboard, we will press the backspace key to delete more than ten texts one by one , When using the virtual keyboard, you need to press the backspace key more than ten times , It doesn't look like it nice. So we use QPushButton Of setAutoRepeat by true, You can press and hold the key , Set the repetition delay to 500ms About the same , Press for longer than 500ms After that, execute the key slot function again .
pbtn->setAutoRepeat(true); // Allow automatic repetition
pbtn->setAutoRepeatDelay(500);// Set the delay of repeated operation 5、 ... and 、 Simulate keyboard click event to complete virtual keyboard input
Some self-made virtual keyboards complete keyboard input in the same way as passing text to the input box , Don't talk much , Just not nice. Clicking the virtual key directly sends the corresponding key click event nice, In this way, you won't die too much , Even Chinese input is ok , We wrote the keyboard , Not writing Chinese input method , Those who download the library containing Chinese input methods on the Internet don't have to , Input method is what your system uses . If you want to input Chinese , The system downloads Sogou input method , Just press your keyboard ctrl+shift Just switch the input method , Instead of realizing the function of Chinese input method in the keyboard . That's not nice, The simulated sending button click event code is as follows .
QPushButton* pbtn = (QPushButton*)sender();
if (pbtn->text() >= 'a' && pbtn->text() <= 'z') {
QKeyEvent keyPress(QEvent::KeyPress, int(pbtn->text().at(0).toLatin1()) - 32, Qt::NoModifier, pbtn->text());
QKeyEvent keyRelease(QEvent::KeyRelease, int(pbtn->text().at(0).toLatin1()) - 32, Qt::NoModifier, pbtn->text());
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}adopt QApplication::sendEvent Sending a key press and key release event is equivalent to simulating a key press event
QKeyEvent explain :
QKeyEvent::QKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text = QString(), bool autorep = false, ushort count = 1)
The type parameter must be QEvent::KeyPress、QEvent::KeyRelease or QEvent::ShortcutOverride.
Int key It is the event loop that should listen Qt:: key Code for . If key by 0, Then the event is not the result of a known key ; for example , It may be the result of combining sequences or keyboard macros . Modifiers include keyboard modifiers , The given text is key generated Unicode Text . If autorep It's true ,isAutoRepeat() Will be true . Count Is the number of keys involved in the event .
QKeyEvent Here we use 4 Just one parameter , The second parameter Qt:: key The corresponding button , The fourth parameter is the text to be sent , Nothing can be entered without this parameter .
QApplication::sendEvent The first parameter of is very important , Is a control that receives keyboard input , For example, the bottom interface lineEdit.
6、 ... and 、 Keyboard symbol input
m_mapSymbolKeys.insert("~", Qt::Key_AsciiTilde);
m_mapSymbolKeys.insert("`", Qt::Key_nobreakspace);
m_mapSymbolKeys.insert("-", Qt::Key_Minus);
m_mapSymbolKeys.insert("_", Qt::Key_Underscore);
m_mapSymbolKeys.insert("+", Qt::Key_Plus);
m_mapSymbolKeys.insert("=", Qt::Key_Equal);
m_mapSymbolKeys.insert(",", Qt::Key_Comma);
m_mapSymbolKeys.insert(".", Qt::Key_Period);
m_mapSymbolKeys.insert("/", Qt::Key_Slash);
m_mapSymbolKeys.insert("<", Qt::Key_Less);
m_mapSymbolKeys.insert(">", Qt::Key_Greater);
m_mapSymbolKeys.insert("?", Qt::Key_Question);
m_mapSymbolKeys.insert("[", Qt::Key_BracketLeft);
m_mapSymbolKeys.insert("]", Qt::Key_BracketRight);
m_mapSymbolKeys.insert("{", Qt::Key_BraceLeft);
m_mapSymbolKeys.insert("}", Qt::Key_BraceRight);
m_mapSymbolKeys.insert("|", Qt::Key_Bar);
m_mapSymbolKeys.insert("\\", Qt::Key_Backslash);
m_mapSymbolKeys.insert(":", Qt::Key_Colon);
m_mapSymbolKeys.insert(";", Qt::Key_Semicolon);
m_mapSymbolKeys.insert("\"", Qt::Key_QuoteLeft);
m_mapSymbolKeys.insert("'", Qt::Key_Apostrophe);
QKeyEvent keyPress(QEvent::KeyPress, m_mapSymbolKeys.value(symbol), Qt::NoModifier, symbol);
QKeyEvent keyRelease(QEvent::KeyRelease, m_mapSymbolKeys.value(symbol), Qt::NoModifier, symbol);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);It is important to find... When inputting specific symbols on the keyboard QKeyEvent The key value corresponding to the second parameter is ok . The values in the keys are all in qnamespace.h In the header file of enum Key Enumeration type .
7、 ... and 、 Interface

8、 ... and 、 Header file code
#pragma once
#pragma execution_character_set("utf-8")
#include <QDialog>
#include "ui_frmKeyBoard.h"
#include "moveWidget.h"
#include <QPushButton>
#include <QKeyEvent>
#include <QDebug>
#include <QStyle>
class frmKeyBoard : public QDialog
{
Q_OBJECT
public:
frmKeyBoard(QWidget *parent = nullptr);
~frmKeyBoard();
void initFocusWidget(QWidget*);
private slots:
void slotKeyButtonClicked();
void slotKeyLetterButtonClicked();
void slotKeyNumberButtonClicked();
private:
Ui::frmKeyBoardClass ui;
void initFrm();
void initStyleSheet();
QWidget* m_focusWidget; // Keyboard input main window
QVector<QPushButton*> m_letterKeys;
QVector<QPushButton*> m_NumberKeys;
QMap<QString, Qt::Key> m_mapSymbolKeys;
};
Nine 、 Source code
#include "frmKeyBoard.h"
frmKeyBoard::frmKeyBoard(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
this->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
this->setWindowTitle(" On screen keyboard ");
this->setWindowModality(Qt::WindowModal);
this->setAttribute(Qt::WA_DeleteOnClose);
MoveWidget* moveWidget = new MoveWidget();
moveWidget->setWidget(this);
this->initFrm();
this->initStyleSheet();
}
frmKeyBoard::~frmKeyBoard()
{
}
void frmKeyBoard::initFocusWidget(QWidget* widget)
{
m_focusWidget = widget;
}
void frmKeyBoard::initFrm()
{
ui.pushButton_closeKeyboard->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
m_letterKeys.clear();
m_NumberKeys.clear();
QList<QPushButton*> pbtns = this->findChildren<QPushButton*>();
foreach(QPushButton * pbtn, pbtns) {
pbtn->setAutoRepeat(true); // Allow automatic repetition
pbtn->setAutoRepeatDelay(500);// Set the delay of repeated operation
if (pbtn->text() >= 'a' && pbtn->text() <= 'z') {
connect(pbtn, &QPushButton::clicked, this, &frmKeyBoard::slotKeyLetterButtonClicked);
m_letterKeys.push_back(pbtn);
}
else if (pbtn->text().toInt() > 0 && pbtn->text().toInt() <= 9 || pbtn->text() == "0") {
connect(pbtn, &QPushButton::clicked, this, &frmKeyBoard::slotKeyNumberButtonClicked);
m_NumberKeys.push_back(pbtn);
}
else{
connect(pbtn, &QPushButton::clicked, this, &frmKeyBoard::slotKeyButtonClicked);
}
}
m_mapSymbolKeys.insert("~", Qt::Key_AsciiTilde);
m_mapSymbolKeys.insert("`", Qt::Key_nobreakspace);
m_mapSymbolKeys.insert("-", Qt::Key_Minus);
m_mapSymbolKeys.insert("_", Qt::Key_Underscore);
m_mapSymbolKeys.insert("+", Qt::Key_Plus);
m_mapSymbolKeys.insert("=", Qt::Key_Equal);
m_mapSymbolKeys.insert(",", Qt::Key_Comma);
m_mapSymbolKeys.insert(".", Qt::Key_Period);
m_mapSymbolKeys.insert("/", Qt::Key_Slash);
m_mapSymbolKeys.insert("<", Qt::Key_Less);
m_mapSymbolKeys.insert(">", Qt::Key_Greater);
m_mapSymbolKeys.insert("?", Qt::Key_Question);
m_mapSymbolKeys.insert("[", Qt::Key_BracketLeft);
m_mapSymbolKeys.insert("]", Qt::Key_BracketRight);
m_mapSymbolKeys.insert("{", Qt::Key_BraceLeft);
m_mapSymbolKeys.insert("}", Qt::Key_BraceRight);
m_mapSymbolKeys.insert("|", Qt::Key_Bar);
m_mapSymbolKeys.insert("\\", Qt::Key_Backslash);
m_mapSymbolKeys.insert(":", Qt::Key_Colon);
m_mapSymbolKeys.insert(";", Qt::Key_Semicolon);
m_mapSymbolKeys.insert("\"", Qt::Key_QuoteLeft);
m_mapSymbolKeys.insert("'", Qt::Key_Apostrophe);
}
void frmKeyBoard::initStyleSheet()
{
QString qss;
qss += "QWidget{ background-color:rgb(26,26,26)}";
qss += "QPushButton{ color:white; background-color:rgb(51,51,51); height:60px; font-size:bold 15pt; border:1px solid rgb(26,26,26); border-radius: 0px; min-width:50px;}";
qss += "QPushButton:hover{background-color:rgb(229,229,229); color:black;}";
qss += "QPushButton:pressed,QPushButton:checked{background-color:rgb(0,118,215);}";
qss += "#pushButton_closeKeyboard{background-color:rgba(0,0,0,0); border:0px}";
qss += "#pushButton_closeKeyboard:hover{background-color:#b30220;}";
qss += "#pushButton_space{min-width:500px;}";
qss += "#pushButton_backspace,#pushButton_shift{min-width:100px;}";
qss += "#pushButton_enter{min-width:120px;}";
qss += "#pushButton_tab,#pushButton_ctrl{min-width:70px;}";
qss += "#pushButton_capsLock{min-width:80px;}";
qss += "#pushButton_up{min-width:150px;}";
this->setStyleSheet(qss);
}
void frmKeyBoard::slotKeyButtonClicked()
{
QPushButton* pbtn = (QPushButton*)sender();
QString objectName = pbtn->objectName();
if (objectName == "pushButton_closeKeyboard") {
this->close();
return;
}
if (pbtn->text().contains("Backspace")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("Caps")) {
if (pbtn->isChecked()) {
for (auto pbtnKey : m_letterKeys) {
pbtnKey->setText(pbtnKey->text().toUpper());
}
}
else {
for (auto pbtnKey : m_letterKeys) {
pbtnKey->setText(pbtnKey->text().toLower());
}
}
}
else if(pbtn->text() == "Space") {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Space, Qt::NoModifier, " ");
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Space, Qt::NoModifier, " ");
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("Tab")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Tab, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("Enter")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("Shift")) {
if (pbtn->isChecked()) {
for (auto pbtnKey : m_letterKeys) {
pbtnKey->setText(pbtnKey->text().toUpper());
}
}
else {
for (auto pbtnKey : m_letterKeys) {
pbtnKey->setText(pbtnKey->text().toLower());
}
}
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Shift, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("Ctrl")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Control, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("Win")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Menu, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Menu, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("Alt")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Alt, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Alt, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("↑")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Up, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("↓")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Down, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("←")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text().contains("→")) {
QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier);
QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else {
QString symbol;
if (ui.pushButton_shift->isChecked())
symbol = pbtn->text().split("\n").at(0);
else
symbol = pbtn->text().split("\n").at(1);
QKeyEvent keyPress(QEvent::KeyPress, m_mapSymbolKeys.value(symbol), Qt::NoModifier, symbol);
QKeyEvent keyRelease(QEvent::KeyRelease, m_mapSymbolKeys.value(symbol), Qt::NoModifier, symbol);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
// Press the cancel key combination
if (!pbtn->text().contains("Shift") && !pbtn->text().contains("Ctrl") && !pbtn->text().contains("Win") && !pbtn->text().contains("Alt")) {
if (ui.pushButton_shift->isChecked()) {
ui.pushButton_shift->setChecked(false);
for (auto pbtnKey : m_letterKeys) {
pbtnKey->setText(pbtnKey->text().toLower());
}
}
if (ui.pushButton_ctrl->isChecked())
ui.pushButton_ctrl->setChecked(false);
if (ui.pushButton_win->isChecked())
ui.pushButton_win->setChecked(false);
if (ui.pushButton_alt->isChecked())
ui.pushButton_alt->setChecked(false);
}
}
void frmKeyBoard::slotKeyLetterButtonClicked()
{
QPushButton* pbtn = (QPushButton*)sender();
if (pbtn->text() >= 'a' && pbtn->text() <= 'z') {
QKeyEvent keyPress(QEvent::KeyPress, int(pbtn->text().at(0).toLatin1()) - 32, Qt::NoModifier, pbtn->text());
QKeyEvent keyRelease(QEvent::KeyRelease, int(pbtn->text().at(0).toLatin1()) - 32, Qt::NoModifier, pbtn->text());
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
else if (pbtn->text() >= 'A' && pbtn->text() <= 'Z') {
QKeyEvent keyPress(QEvent::KeyPress, int(pbtn->text().at(0).toLatin1()), Qt::NoModifier, pbtn->text());
QKeyEvent keyRelease(QEvent::KeyRelease, int(pbtn->text().at(0).toLatin1()), Qt::NoModifier, pbtn->text());
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
}
// Press the cancel key combination
if (ui.pushButton_shift->isChecked()) {
ui.pushButton_shift->setChecked(false);
for (auto pbtnKey : m_letterKeys) {
pbtnKey->setText(pbtnKey->text().toLower());
}
}
if (ui.pushButton_ctrl->isChecked())
ui.pushButton_ctrl->setChecked(false);
if (ui.pushButton_win->isChecked())
ui.pushButton_win->setChecked(false);
if (ui.pushButton_alt->isChecked())
ui.pushButton_alt->setChecked(false);
}
void frmKeyBoard::slotKeyNumberButtonClicked()
{
QPushButton* pbtn = (QPushButton*)sender();
QKeyEvent keyPress(QEvent::KeyPress, pbtn->text().toInt() + 48, Qt::NoModifier, pbtn->text());
QKeyEvent keyRelease(QEvent::KeyRelease, pbtn->text().toInt() + 48, Qt::NoModifier, pbtn->text());
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyPress);
QApplication::sendEvent(m_focusWidget->focusWidget(), &keyRelease);
// Press the cancel key combination
if (ui.pushButton_shift->isChecked()) {
ui.pushButton_shift->setChecked(false);
for (auto pbtnKey : m_letterKeys) {
pbtnKey->setText(pbtnKey->text().toLower());
}
}
if (ui.pushButton_ctrl->isChecked())
ui.pushButton_ctrl->setChecked(false);
if (ui.pushButton_win->isChecked())
ui.pushButton_win->setChecked(false);
if (ui.pushButton_alt->isChecked())
ui.pushButton_alt->setChecked(false);
}
11、 ... and 、 effect

Qt Self made virtual keyboard
Twelve 、 Download resources
边栏推荐
- 30 day question brushing plan (II)
- The strongest distributed locking tool: redisson
- [lvgl events] Application of events on different components (I)
- Operator3 - design an operator
- 作为一个程序员,如何高效的管理时间?
- Socket class understanding and learning about TCP character stream programming
- On websocket
- P1797 heavy transportation problem solution
- 30 day question brushing training (I)
- Three cases of thread blocking.
猜你喜欢

Entering the world of audio and video -- flv video packaging format

strcmp、strstr、memcpy、memmove的实现

IP黑白名单

在centos中安装mysql5.7.36

Diablo 4 ps4/ps5 beta has been added to the Playstation database

修订版 | 目标检测:速度和准确性比较(Faster R-CNN,R-FCN,SSD,FPN,RetinaNet和YOLOv3)...

走进音视频的世界——FLV视频封装格式

多线程与高并发(三)—— 源码解析 AQS 原理

QT自制软键盘 最完美、最简单、跟自带虚拟键盘一样

Redis sentinel mechanism
随机推荐
R language Visual scatter diagram, geom using ggrep package_ text_ The repl function avoids overlapping labels between data points (add labels to specific areas of the visual image using the parameter
DXF reading and writing: align the calculation of the position of the dimension text in the middle and above
Slam thesis collection
【LVGL事件(Events)】事件在不同组件上的应用(一)
P1797 heavy transportation problem solution
Power amplifier and matching network learning
7.27模拟赛总结
leetcode(442)数组中重复的数据
安全保障基于软件全生命周期-NetworkPolicy应用
Do you really know esmodule
R language uses LM function to build multiple linear regression model, writes regression equation according to model coefficient, and uses conflict function to give 95% confidence interval of regressi
作为一个程序员,如何高效的管理时间?
Jmeter安装教程及登录增加token
LeetCode 0142.环形链表 II
MySql5.5之后的默认存储引擎为InnoDB。
What is a spin lock? A spin lock means that when a thread attempts to acquire a lock, if the lock has been occupied by other threads, it will always cycle to detect whether the lock has been released,
Three cases of thread blocking.
strcmp、strstr、memcpy、memmove的实现
在centos中安装mysql5.7.36
【服务器数据恢复】HP StorageWorks系列服务器RAID5两块盘离线的数据恢复