如何防止过度打字

时间:2012-12-16 03:55:52

标签: c++

我正在尝试用c ++制作一个简单的聊天应用程序。它有效,但是,如果有人在其他人打字的时候输入了某些内容。它喜欢写下他们输入的内容。我将图片链接为以下示例。

我在客户端和服务器上使用的代码可以在这里找到:

Client

Server

图片:

enter image description hereenter image description here

3 个答案:

答案 0 :(得分:7)

一种方法是在用户第一次开始键入一行文本时设置标志 - 然后如果在设置该标志时从网络接收数据,则只需将接收到的数据排成一些本地数据结构(即不要打印它,直到本地用户按下返回。当本地用户按下返回时,您将打印出您在键入时排队的所有数据,并取消设置该标志。

当然,这种方法有几个缺点:

  • 如果本地用户输入了一些文字并且从不按回复,他将永远不会看到任何传入的远程文本。这可能是一个问题,例如如果用户按下空格并离开。
  • C / C ++中的cin / stdin功能通常以每行为基础工作,您需要将终端设置为原始/非规范模式,以便在本地用户只输入一个字符时进行报告(而不是在本地用户按下返回之前缓冲字符,然后立即将整行文本报告给您的程序)

另一种方法是将本地用户的文本和远程用户的文本保存在物理上独立的区域(例如,窗口的上半部分和下半部分,就像许多聊天程序一样)。要做到这一点,需要比vanilla C / C ++ stdin / stdout / cin / cout API给你更多的控制;您需要创建一个GUI窗口(使用Win32或Qt或其他GUI API)和两个单独的文本窗口小部件,或者如果您想将所有内容保存在MS-DOS窗口中,您可能会使用{{3实现它。

但是,这些选项中的任何一个都是非平凡的 - 它们可能比其他聊天应用程序花费更多的时间和精力来实现。如果是我,聊天应用程序只是一个学习练习,我很想简单地将当前行为记录为“已知限制”,而不用担心修复它。

答案 1 :(得分:2)

杰里米的帖子相当彻底。我将添加另一个可供您使用的选项:跟踪正在输入的用户输入的字符,直到他最后按下ENTER。这样,当远程用户输入文本时,您只需要这样做:

向终端写入适当数量的退格字符('\ b')(即与本地用户键入的文本长度一样多),然后输出新的输入文本行,然后输出所有本地用户之前键入的字符。然后继续正常。

看起来好像新的传入文本“滑动”到位。

答案 2 :(得分:1)

#include <Conio.h>
#include <mutex> // C++11, if not C++11 find your own mutex

std::vector<char> inputBuffer;
std::mutex inputGuard;
struct Locker {
  std::mutex* m;
  Locker(std::mutex& m_):m(&m_) { m->lock(); }
  void release() { if (m) m->unlock(); m = 0; }
  ~Locker() { release(); }
}
void AddToInputBuffer( char c ) {
  Locker lock(inputGuard);
  inputBuffer.push_back(c);
  printf("%c",c);
}
std::string FinishInputBuffer() {
  Locker lock(inputGuard);
  std::string retval( inputBuffer.begin(), inputBuffer.end() );
  inputBuffer.clear();
  printf("\n");
  return retval;
}
void OverlappedPrintln( std::string s ) {
  Locker lock(inputGuard);
  for (int i = 0; i < inputBuffer.size(); ++i) {
    printf("%c", 8 /*backspace*/);
  }
  printf("%s\n", s.c_str());
  for (int i = 0; i < inputBuffer.size(); ++i) {
    printf("%c", inputBuffer[i]);
  }
}

std::string readCharactersFromUser() {
  // TODO: Handle exiting
  while( int input = getch() ) {
    if (input == '\n') {
      return FinishInputBuffer();
    AddToInputBuffer(input);
  }
}

现在,将cin.getline(message, 256);替换为std::string message = readCharactersFromuser(),然后在执行string之前检查(message[0] == 's' && message[1] == 'a' && message[2] == 'y' && message[3] == ' '的长度。

在程序的其他地方,printf,而是构建std::string并与之联系OverlappedPrintln

这样做的效果是,当您想要打印出来的东西时,您可以锁定互斥锁,退回用户输入,打印消息,换行,然后打印出您退回的文本,然后释放互斥锁。在99%的情况下不需要互斥锁,特别是在现代计算机速度的情况下,但这是一种很好的做法。

上述代码未经过测试或编译。也不是最高质量的。

非回显get字符的选择是因为我无法读取锁中的用户输入,并且异步回显输出可能会导致文本出现乱码。所以我在没有回声的情况下读取,然后在互斥锁内回声,这样inputBuffer总是包含用户键入的字符,并且我已经回显到屏幕。

这是@NikBougalis回答的实现。