Merge remote-tracking branch 'origin/main'
# Conflicts: # PCB/Moonshine_travelers.eprj2
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
|
||||
## 2026-05-03 工作日志
|
||||
|
||||
### 添加中文输入法到 CannedMessageModule
|
||||
|
||||
**修改的文件:**
|
||||
- `src/modules/CannedMessageModule.h` - 添加 InputMode::CHINESE 枚举值,添加中文输入相关成员变量和方法声明
|
||||
- `src/modules/CannedMessageModule.cpp` - 实现中文输入法逻辑
|
||||
|
||||
**实现的功能:**
|
||||
1. 在 `InputMode` 枚举中添加 `CHINESE`,支持4种输入模式切换(DIGIT/LOWER/UPPER/CHINESE)
|
||||
2. 修改 `#` 键切换逻辑:`(m + 1) % 4` 支持4种模式
|
||||
3. 在 `handleFreeTextInput()` 中添加中文模式检查,调用 `handleChineseInput()`
|
||||
4. 实现 `handleChineseInput()` 方法:
|
||||
- 数字键1-6选择常用汉字(我/你/他/是/的/好)
|
||||
- `*` 键删除最后一个字符(正确处理UTF-8中文编码)
|
||||
- SELECT键切换回字母输入模式
|
||||
5. 实现 `drawChineseInput()` 方法:绘制中文输入界面
|
||||
|
||||
**使用方式:**
|
||||
- 在文本输入界面按 `#` 键切换到中文模式
|
||||
- 按数字键1-6选择汉字
|
||||
- 按 `*` 键删除字符
|
||||
- 按 SELECT 键退出中文模式
|
||||
|
||||
**限制:**
|
||||
- 当前只支持6个常用汉字
|
||||
- 未实现拼音输入法(需要更大的字典)
|
||||
- 后续可扩展为支持翻页(按"0"键)和更多汉字
|
||||
|
||||
@@ -57,6 +57,12 @@ const char *const CannedMessageModule::t9LetterMap[][5] = {
|
||||
#include "graphics/fonts/ChineseFont12x12.h"
|
||||
#include <Throttle.h>
|
||||
|
||||
// === 中文输入法:常用汉字列表(6个)===
|
||||
// 在 handleChineseInput() 和 drawChineseInput() 方法中硬编码使用
|
||||
// 格式:数字键 -> 汉字
|
||||
static const char* chineseChars[] = {"我", "你", "他", "是", "的", "好"};
|
||||
|
||||
|
||||
// Remove Canned message screen if no action is taken for some milliseconds
|
||||
#define INACTIVATE_AFTER_MS 20000
|
||||
|
||||
@@ -786,6 +792,11 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
|
||||
if (runState != CANNED_MESSAGE_RUN_STATE_FREETEXT)
|
||||
return false;
|
||||
|
||||
// === 中文输入模式处理 ===
|
||||
if (inputMode == InputMode::CHINESE) {
|
||||
return handleChineseInput(event);
|
||||
}
|
||||
|
||||
#if defined(USE_VIRTUAL_KEYBOARD)
|
||||
// Cancel (dismiss freetext screen)
|
||||
if (event->inputEvent == INPUT_BROKER_LEFT) {
|
||||
@@ -961,12 +972,12 @@ bool CannedMessageModule::handleFreeTextInput(const InputEvent *event)
|
||||
return true;
|
||||
}
|
||||
|
||||
// '#' key: cycle input mode DIGIT -> LOWER -> UPPER -> DIGIT ...
|
||||
// '#' key: cycle input mode DIGIT -> LOWER -> UPPER -> CHINESE -> DIGIT ...
|
||||
if (event->kbchar == '#') {
|
||||
// First, commit any pending multi-tap character
|
||||
commitMultiTap();
|
||||
int m = static_cast<int>(inputMode);
|
||||
inputMode = static_cast<InputMode>((m + 1) % 3);
|
||||
inputMode = static_cast<InputMode>((m + 1) % 4); // 修改为 %4,支持4种模式
|
||||
LOG_DEBUG("[T9] Input mode: %d", (int)inputMode);
|
||||
lastTouchMillis = millis();
|
||||
// Use REDRAW_ONLY: commitMultiTap() already triggered REGENERATE_FRAMESET,
|
||||
@@ -1080,6 +1091,96 @@ int CannedMessageModule::handleEmotePickerInput(const InputEvent *event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// === 中文输入法:数字选择汉字 ===
|
||||
bool CannedMessageModule::handleChineseInput(const InputEvent *event)
|
||||
{
|
||||
// 数字键1-6:选择对应的汉字
|
||||
if (event->kbchar >= '1' && event->kbchar <= '6') {
|
||||
// 常用汉字列表(6个)
|
||||
static const char* chineseChars[] = {"我", "你", "他", "是", "的", "好"};
|
||||
int index = event->kbchar - '1';
|
||||
|
||||
// 插入选中的汉字到 freetext
|
||||
String chineseChar = chineseChars[index];
|
||||
if (cursor >= freetext.length()) {
|
||||
freetext += chineseChar;
|
||||
} else {
|
||||
freetext = freetext.substring(0, cursor) + chineseChar + freetext.substring(cursor);
|
||||
}
|
||||
cursor += chineseChar.length();
|
||||
|
||||
lastTouchMillis = millis();
|
||||
screen->forceDisplay();
|
||||
return true;
|
||||
}
|
||||
|
||||
// * 键或 BACK 键:删除最后一个字符
|
||||
if (event->kbchar == '*' || event->inputEvent == INPUT_BROKER_BACK) {
|
||||
if (freetext.length() > 0) {
|
||||
// 简化处理:删除最后1-3个字节(UTF-8中文是3字节)
|
||||
// 找到最后一个UTF-8字符的起始位置
|
||||
int lastPos = freetext.length() - 1;
|
||||
while (lastPos >= 0 && (freetext[lastPos] & 0xC0) == 0x80) {
|
||||
lastPos--; // 向前找到UTF-8字符的起始字节
|
||||
}
|
||||
if (lastPos >= 0) {
|
||||
freetext.remove(lastPos);
|
||||
if (cursor > lastPos) {
|
||||
cursor = lastPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastTouchMillis = millis();
|
||||
screen->forceDisplay();
|
||||
return true;
|
||||
}
|
||||
|
||||
// SELECT 键:切换回其他输入模式(或确认输入)
|
||||
if (isSelectEvent(event)) {
|
||||
// 切换到小写字母模式,继续输入
|
||||
inputMode = InputMode::LOWER;
|
||||
lastTouchMillis = millis();
|
||||
screen->forceDisplay();
|
||||
return true;
|
||||
}
|
||||
|
||||
// 其他按键:不处理
|
||||
return false;
|
||||
}
|
||||
|
||||
// === 绘制中文输入界面 ===
|
||||
void CannedMessageModule::drawChineseInput(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// 常用汉字列表(6个)
|
||||
static const char* chineseChars[] = {"我", "你", "他", "是", "的", "好"};
|
||||
|
||||
// 设置字体(使用支持中文的字体)
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
// 绘制标题
|
||||
display->drawString(0, 0, "中文输入:");
|
||||
|
||||
// 绘制已输入的文本
|
||||
if (freetext.length() > 0) {
|
||||
display->drawString(0, 16, "文本:" + freetext);
|
||||
}
|
||||
|
||||
// 绘制候选汉字(在屏幕底部)
|
||||
int startY = display->getHeight() - 16; // 从底部向上绘制
|
||||
int xPos = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
String label = String(i+1) + ":" + String(chineseChars[i]);
|
||||
display->drawString(xPos, startY, label);
|
||||
xPos += 40; // 每个候选字间隔40像素
|
||||
if (xPos > display->getWidth() - 40) {
|
||||
xPos = 0;
|
||||
startY -= 16; // 换行
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const char *message, bool wantReplies)
|
||||
{
|
||||
lastDest = dest;
|
||||
@@ -1906,6 +2007,13 @@ void CannedMessageModule::drawEmotePickerScreen(OLEDDisplay *display, OLEDDispla
|
||||
void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
this->displayHeight = display->getHeight(); // Store display height for later use
|
||||
|
||||
// === 中文输入模式界面 ===
|
||||
if (inputMode == InputMode::CHINESE) {
|
||||
drawChineseInput(display, state, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[50];
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
@@ -194,7 +194,7 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
#endif
|
||||
|
||||
// === Multi-tap T9 input method (for TCA9535 numpad) ===
|
||||
enum class InputMode : uint8_t { DIGIT, LOWER, UPPER };
|
||||
enum class InputMode : uint8_t { DIGIT, LOWER, UPPER, CHINESE };
|
||||
InputMode inputMode = InputMode::LOWER; // 默认小写字母模式
|
||||
uint8_t multiTapKey = 0xFF; // 上一次按的数字键 ('0'-'9'), 0xFF = no pending key
|
||||
uint8_t multiTapIndex = 0; // 当前循环索引
|
||||
@@ -213,6 +213,15 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
bool commitMultiTap(); // Returns true if a character was actually committed
|
||||
void showMultiTapPreview();
|
||||
|
||||
// === 中文输入法相关方法 ===
|
||||
bool handleChineseInput(const InputEvent *event); // 处理中文输入模式的按键
|
||||
void drawChineseInput(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); // 绘制中文输入界面
|
||||
|
||||
// === 中文输入法相关成员变量 ===
|
||||
String chinesePinyin; // 当前输入的拼音
|
||||
String chineseCandidates; // 候选汉字字符串(用逗号分隔)
|
||||
int chineseCandidateIndex; // 当前选中的候选字索引
|
||||
|
||||
#if defined(USE_VIRTUAL_KEYBOARD)
|
||||
Letter keyboard[2][4][10] = {{{{"Q", 20, 0, 0, 0, 0},
|
||||
{"W", 22, 0, 0, 0, 0},
|
||||
|
||||
Reference in New Issue
Block a user