Thread: Moving the cursor around.

  1. #1
    Registered User
    Join Date
    Aug 2004
    Location
    San Diego, CA
    Posts
    313

    Moving the cursor around.

    I'm currently writing a very basic chatting client/server combo using the Windows console. I have successfully gotten Winsock established, and have used threads to allow for asynchronious chatting. However, this causes a problem.

    When I chat with someone, there are two very strange conditions that can occur. First, if I am typing and they send, there is a condition that looks something like this:

    Server: I am the server. I am typing aClient: Hiya! I'm the client!
    sentince to you.
    And then, if that is not met, I get this type of problem:

    Client: This is me typing a sentince.
    Client: Now I am going to wait at the Client: prompt to think of another one.
    Client:
    Server: HI! I'm the server butting in!
    What I would LIKE to do to solve both problems is to move the cursor around, and/or write the text only after it is input. The easiest way to do that would be to move text around. For example..

    The client is writing a sentince when data from the server comes in. The current line the client is writing is cleared, then the server stuff is printed, and then the client's line is put below the server's stuff. Keeping the output clean.

    I just have no idea how to do this. Help?

    (And yes, I have tried SetConsoleCursorPosition(), but it doesn't work for what I want, at least how I used it.)


    Server

    Code:
    // Multiple User Role-Play
    // Version 0.2s
    // By: Steven Merrick
    
    #include <iostream>
    #include <winsock.h>
    
    int GetClientInput(SOCKET s);
    
    int main()
    {
    	int tmp;
    	char buffer[256];
    	
    	WSADATA wsaData; // Windows Socket Data.
    	SOCKET sListen, sClient; // Create listening socket.
    	SOCKADDR_IN sInfo;
    		sInfo.sin_family = AF_INET; // Internet.
    		sInfo.sin_addr.s_addr = INADDR_ANY; // Any incoming address.
    		sInfo.sin_port = htons(10000); // Port 10000.
    	HANDLE sThread;
    	DWORD sTID;
    	
    	tmp = WSAStartup(MAKEWORD(1,1), &wsaData); // Initialize Winsock 1.1.
    	
    	if (tmp == SOCKET_ERROR)
    	{
    		std::cout << "Error in initializing Winsock: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    	
    	sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Create an Internet Steam TCP Socket.
    	
    	if (sListen == INVALID_SOCKET) 
    	{
    		std::cout << "Error in creating socket: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    		
    	tmp = bind(sListen, (LPSOCKADDR)&sInfo, sizeof(struct sockaddr));
    	
    	if (tmp == SOCKET_ERROR)
    	{
    		std::cout << "Error in binding socket: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    	
    	tmp = listen(sListen, 1);
    	
    	if (tmp == SOCKET_ERROR)
    	{
    		std::cout << "Error in listening: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    	
    	sClient = accept(sListen, NULL, NULL);
    	
    	if (sClient == SOCKET_ERROR)
    	{
    		std::cout << "Error in accepting: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    	
    	sThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)GetClientInput, (LPVOID)sClient, 0, &sTID); // Starts thread to get input from user.
    
    	while (sClient != SOCKET_ERROR)
    	{
    		memset(buffer, NULL, sizeof(buffer)); // Clears the buffer.
    		recv(sClient, buffer, sizeof(buffer), 0); // Gets data.
    		
    		if (buffer[0] != NULL) // If the buffer is not empty..
    		{
    			std::cout << "Client: " << buffer << "\n"; // Outputs information gotten from other client(s).
    		}
    	}
    	
    	// Close sockets cleanly, shutdown Winsock.
    	
    	closesocket(sClient);
    	closesocket(sListen);
    	WSACleanup();
    	
    	std::cin.get();
    	
    	return(0);
    }
    
    int GetClientInput(SOCKET s)
    {
    	char buffer[256];
    	
    	while (s != SOCKET_ERROR)
    	{		
    		memset(buffer, 0, sizeof(buffer)); // Clears the buffer.
    				
    		std::cin.getline(buffer, 256);// Gets user input.
    		
    		send(s, buffer, strlen(buffer), 0); // Sends user input to other client(s).
    	}
    	
    	return(0);
    }
    Client

    Code:
    // Multiple User Role-Play
    // Version 0.2c
    // By: Steven Merrick
    
    #include <iostream>
    #include <winsock.h>
    
    int GetClientInput(SOCKET s);
    
    int main()
    {
    	int tmp;
    	char buffer[256];
    	
    	WSADATA wsaData; // Windows Socket Data.
    	SOCKET sClient; // Create client socket.
    	HANDLE sThread, rThread; // Thread handle.
    	DWORD sTID, rTID; // Thread ID.
    	
    	tmp = WSAStartup(MAKEWORD(1,1), &wsaData); // Initialize Winsock 1.1.
    	
    	if (tmp == SOCKET_ERROR)
    	{
    		std::cout << "Error in initializing Winsock: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    	
    	LPHOSTENT hEntry;
    	hEntry = gethostbyname("lithorien.net"); // Resolves the domain 'lithorien.net'.
    	
    	if (!hEntry) 
    	{
    		std::cout << "Error in resolving host: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    	
    	SOCKADDR_IN sInfo;
    		sInfo.sin_family = AF_INET; // Internet.
    		sInfo.sin_addr = *((LPIN_ADDR)*hEntry->h_addr_list); // Lithorien.net, first preferred IP.
    		sInfo.sin_port = htons(10000); // Port 10000.
    	
    	sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Create an Internet Steam TCP Socket.
    	
    	if (sClient == INVALID_SOCKET) 
    	{
    		std::cout << "Error in creating socket: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    	
    	tmp = connect(sClient, (LPSOCKADDR)&sInfo, sizeof(struct sockaddr));
    	
    	if (tmp == SOCKET_ERROR)
    	{
    		std::cout << "Error in initializing Winsock: " << WSAGetLastError(); // Cout an error message.
    		WSACleanup(); // Shutdown Winsock
    	}
    	
    	sThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)GetClientInput, (LPVOID)sClient, 0, &sTID); // Starts thread to get input from user.
    		
    	// Gets information from the server.
    	
    	while (sClient != SOCKET_ERROR)
    	{
    		memset(buffer, NULL, sizeof(buffer)); // Clears the buffer.
    		recv(sClient, buffer, sizeof(buffer), 0); // Gets data.
    		
    		if (buffer[0] != NULL) // If the buffer is not empty..
    		{			
    			std::cout << "\nServer: " << buffer << "\n"; // Outputs information gotten from other client(s).
    		}
    	}
    	
    	closesocket(sClient); // Close socket cleanly.
    	WSACleanup(); // Shutdown Winsock
    	
    	std::cin.get();
    	
    	return(0);
    }
    
    int GetClientInput(SOCKET s)
    {
    	char buffer[256];
        
    	while (s != SOCKET_ERROR)
    	{		
    		memset(buffer, 0, sizeof(buffer)); // Clears the buffer.
    		
    		std::cout << "Client: ";
    		std::cin.getline(buffer, 256); // Gets user input.
    		
    		send(s, buffer, strlen(buffer), 0); // Sends user input to other client(s).
    	}
    	
    	return(0);
    }


    Edit: This should probally be in the Windows Programming section. Sorry for the misplace.
    Last edited by Lithorien; 12-25-2004 at 04:14 PM.

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Why don't you have a field you type your text into and when you hit enter, it sends the whole string? You've used some other IM/chat programs in the past I assume. That's the method they all use. Basicly, you buffer the input until a sentence is done, (IE you hit enter) and then send the whole sentence at once. Sentences (or pharagraphs, whatever) would be displayed in the order they are received.

    In other words, why don't you just buffer your IO?

    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Aug 2004
    Location
    San Diego, CA
    Posts
    313
    Quote Originally Posted by quzah
    Why don't you have a field you type your text into and when you hit enter, it sends the whole string? You've used some other IM/chat programs in the past I assume. That's the method they all use. Basicly, you buffer the input until a sentence is done, (IE you hit enter) and then send the whole sentence at once. Sentences (or pharagraphs, whatever) would be displayed in the order they are received.

    In other words, why don't you just buffer your IO?

    Quzah.
    I am buffering my I/O. The problem is that if the I/O is sent from one side before the other side is done typing (EG: They are mid-sentince), the recieved data displays in the middle of the input stream.

    I don't want to hold the data back to wait for each person to send a message, one message at a time, either, because then it defeats the purpose of making the server asynchronious, and I could just have a message loop such as

    Code:
    while (sClient != SOCKET_ERROR)
    	{
    		memset(buffer, 0, sizeof(buffer));
    		
    		std::cout << "Client: ";			
    		std::cin.getline(buffer, 256);
    		send(sClient, buffer, strlen(buffer), 0);
    		std::cout << "\n";
    		
    		memset(buffer, 0, sizeof(buffer));
    		
    		recv(sClient, buffer, sizeof(buffer), 0);
    		std::cout << "Server: " << buffer << "\n";
    	}
    This is a console project as well, which means I can't have a seperate input / output area, as far as I know.

  4. #4
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    So how about not sending the output when it's received until they hit enter? Then, if any is pending, write it. Otherwise, wait on it.

    You're really going to have to redesign how you do this. The problem is this:

    1) Your keyboard input is buffered.
    2) Your output is not.

    What happens then, is you're not reading each keystroke as it happens. If you were, you could do the following:
    Code:
    typing typing typing<message from someone else interrupts>
    <drop to new line>
    <display interrupting message>
    <drop to new line>
    <display "typing typing" input which you've captured key by key>it now resumes on that line
    Giving you something like:
    Code:
    Me: Hello there. It'
    You: My C++ program doesn't work right can you help?
    Me: Hello there. It's cold here today.
    What you do in this scenario is read "non buffered" into a buffer until a newline is entered. When it is, you send everything you have buffered to the other connections. However, to do this, you'll have to look up how to read non-buffered input.

    If you don't like that idea, then you're going to need to look into something similar to the curses library so you can make a seperate input window. (Which is a much cleaner approach.)

    Moving the cursor around isn't really going to help this situation much, unless you sort of make your own implementation of "windowing" and such.

    Quzah.
    Last edited by quzah; 12-25-2004 at 04:38 PM. Reason: Fixing hscroll.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Moving Average Question
    By GCNDoug in forum C Programming
    Replies: 4
    Last Post: 04-23-2007, 11:05 PM
  2. moving median function
    By supermeew in forum C Programming
    Replies: 0
    Last Post: 05-04-2006, 02:37 PM
  3. Replies: 4
    Last Post: 01-16-2006, 05:58 PM
  4. 3D moving
    By bluehead in forum C++ Programming
    Replies: 9
    Last Post: 04-02-2005, 05:46 AM
  5. Simple program i cant get (dot moving)
    By Lupusk9 in forum C++ Programming
    Replies: 4
    Last Post: 09-14-2004, 08:04 PM