Page 1 of 2

How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 6:21 am
by DixiumOS
For a shell, I need a part of a function get the cursor position.

However, I can't find any documentation or code that shows how i can get the cursor position.
How do I get this?

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 6:24 am
by iansjack

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 6:25 am
by DixiumOS
iansjack wrote:http://wiki.osdev.org/Text_Mode_Cursor
I meant get the cursor location/position, not setting it. I already have a function that sets the cursor.

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 6:27 am
by matt11235
Why do you need to get it again? Why not just store the position of the cursor in your code?

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 6:28 am
by iansjack
I've been following your train-wreck on #osdev. You don't listen so there is little point in anyone wasting their time to help you.

One last try. The text cursor is at 0, 0 until you put it somewhere else. And then you know where it is.

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 6:34 am
by DixiumOS
zenzizenzicube wrote:Why do you need to get it again? Why not just store the position of the cursor in your code?
Yep, I should do that.

EDIT: Got it, but i get a space character every time i release a key.

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 6:46 am
by TheDev100
Use INT 10h. Go to Wikipedia. That's a nice reference. Learn Assembly instead! C is useless. Assembly is great. Look how many good projects are written 100% fully in Assembly.

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 6:50 am
by DixiumOS
TheDev100 wrote:Use INT 10h. Go to Wikipedia. That's a nice reference. Learn Assembly instead! C is useless. Assembly is great. Look how many good projects are written 100% fully in Assembly.
I'm in Protected Mode (you can't use int 10h) and thanks but I'm not switching to Assembly, i prefer C/C++.

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 7:06 am
by ThinkingMind
In case you do not know how to print a character, read the following.
In case you already know how to print a character, still read the following.

0xB8000 | character at (0, 0) |
0xB8001 | color of character at (0, 0) |
0xB8002 | character at (1, 0) |
0xB8003 | color of character at (1, 0) |
0xB8004 | character at (2, 0) |
0xB8005 | color of character at (2, 0) |
0xB8006 | character at (3, 0) |
0xB8007 | color of character at (3, 0) |
.
.
.

To improve performance, you should store the cursor's position in two variables and update the cursor whenever necessary. By doing so, we will avoid reading from the controller. Also when you are OS starts, you would want to start printing text from (0, 0) right?

Code: Select all

int x = 0, y = 0;
If you observe the memory layout I posted at the start, you can derive the following formula which tells you the memory location where the character at (x, y) is stored:

location = 0xB8000 + (y*80 + x)*2

Why 80? There are 80 characters per line.
Why 2? The first byte is used to store the character and the next byte is used to store the color/attribute. So each character takes up two bytes.

You would want to have a common color for all characters, so you store the color information it in a variable.

Code: Select all

static uint8_t attribute = 0x0F;
To display a character on the screen, all you have to do is write to the correct memory location. Nothing to do with the hardware.

Code: Select all

static void putc(unsigned char c) 
{	
     uint16_t *where = 0xB8000 + (y *80 + x);
     *where = c | (attribute << 8);
   
      x++;
      if(x == 80)
      {
           x = 0;
           y++;
      }
}
x, y always has the position of the next character to be printed.

Where should the cursor appear?

"Hiiiiiiiii_"
..........^ the cursor should appear in the location of the next character to be printed

so that means that x, y are essentially storing the cursor's new position.

Unlike displaying characters on screen, the cursor has to be updated by talking to the CRT controller using the in/out instruction.
The controller accepts the position as:

cursor position = y*80 + x

25*80 = 2000, this would mean the cursor position cannot be stored in a byte. You'd need at least two bytes.

Unfortunately, you cannot send two bytes of data in a single out instruction to the CRT controller. You have to split it into two bytes and send separately.

Code: Select all

unsigned int temp = y * 80 + x;

    outportb(0x3D4, 0xE);
    outportb(0x3D5, temp >> 8);
    outportb(0x3D4, 0xF);
    outportb(0x3D5, temp);
So everytime you print a character, you must update the cursor.

The final code would look something like this:

Code: Select all

static void putc(unsigned char c) 
{	
     uint16_t *where = 0xB8000 + (y *80 + x);
     *where = c | (attribute << 8);
   
      x++;
      if(x == 80)
      {
           x = 0;
           y++;
      }
      unsigned int temp = y * 80 + x;

      outportb(0x3D4, 0xE);
      outportb(0x3D5, temp >> 8);
      outportb(0x3D4, 0xF);
      outportb(0x3D5, temp);
}
You'll never need to read the location from the controller because you already have it :)
You might also want to update the cursor when your OS starts so that it moves to zero (in case it had been moved somewhere else by the bootloader or BIOS or whatever). Might also want to clear the screen? That is for you to write after reading this post (fill the screen with spaces).

The code I gave does not handle null character, carriage return, backspace, etc. Here is a better (more complete) version of the same.

Code: Select all

static void putc(unsigned char c) 
{	
	switch(c)
	{
		case '\0': return;
		case '\b':
			if(curPos_x != 0) curPos_x--;
		break;
		
		case ' ':
			curPos_x++;
		break;
		
		case '\t':
			curPos_x = (curPos_x + 8) & ~(8 - 1);
		break;
		
		case '\r':
			curPos_x = 0;
		break;
		
		case '\n':
			curPos_x = 0;
			curPos_y++;
		break;
		
		default:
		{
			if(isprint(c))
			{
				uint16_t *where = vmemptr + (curPos_y * TEXTMODE_MAX_X + curPos_x);
				*where = c | (attribute << 8);
				curPos_x++;
			}
			break;
		}
	}	
	if(curPos_x >= TEXTMODE_MAX_X)
    {
        curPos_x = 0;
        curPos_y++;
    }	
    if(curPos_y >= TEXTMODE_MAX_Y)
    {
		uint16_t blank = 0x20 | (attribute << 8);
        uint16_t temp = curPos_y - TEXTMODE_MAX_Y + 1;
        memcpy (vmemptr, vmemptr + temp * TEXTMODE_MAX_X, (TEXTMODE_MAX_Y - temp) * TEXTMODE_MAX_X * 2);
        memsetw (vmemptr + (TEXTMODE_MAX_Y - temp) * TEXTMODE_MAX_X, blank, TEXTMODE_MAX_X);
        curPos_y = TEXTMODE_MAX_Y - 1;
    }
	updatecursor();
}
When you are printing strings, you should update the cursor only once. Not every time you print a character. So instead of having update cursor in putc, add it in your puts.

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 7:12 am
by DixiumOS
ThinkingMind wrote:In case you do not know how to print a character, read the following.
In case you already know how to print a character, still read the following.

0xB8000 | character at (0, 0) |
0xB8001 | color of character at (0, 0) |
0xB8002 | character at (1, 0) |
0xB8003 | color of character at (1, 0) |
0xB8004 | character at (2, 0) |
0xB8005 | color of character at (2, 0) |
0xB8006 | character at (3, 0) |
0xB8007 | color of character at (3, 0) |
.
.
.

To improve performance, you should store the cursor's position in two variables and update the cursor whenever necessary. By doing so, we will avoid reading from the controller. Also when you are OS starts, you would want to start printing text from (0, 0) right?

Code: Select all

int x = 0, y = 0;
If you observe the memory layout I posted at the start, you can derive the following formula which tells you the memory location where the character at (x, y) is stored:

location = 0xB8000 + (y*80 + x)*2

Why 80? There are 80 characters per line.
Why 2? The first byte is used to store the character and the next byte is used to store the color/attribute. So each character takes up two bytes.

You would want to have a common color for all characters, so you store the color information it in a variable.

Code: Select all

static uint8_t attribute = 0x0F;
To display a character on the screen, all you have to do is write to the correct memory location. Nothing to do with the hardware.

Code: Select all

static void putc(unsigned char c) 
{	
     uint16_t *where = 0xB8000 + (y *80 + x);
     *where = c | (attribute << 8);
   
      x++;
      if(x == 80)
      {
           x = 0;
           y++;
      }
}
x, y always has the position of the next character to be printed.

How should the cursor appear?

"Hiiiiiiiii_"
...........^ the cursor should appear in the location of the next character to be printed

so that means that x, y are essentially storing the cursor's new position.

Unlike displaying characters on screen, the cursor has to be updated by talking to the CRT controller using the in/out instruction.
The controller accepts the position as:

cursor position = y*80 + x

25*80 = 2000, this would mean the cursor position cannot be stored in a byte. You'd need at least two bytes.

Unfortunately, you cannot send two bytes of data in a single out instruction to the CRT controller. You have to split it into two bytes and send separately.

Code: Select all

unsigned int temp = y * 80 + x;

    outportb(0x3D4, 0xE);
    outportb(0x3D5, temp >> 8);
    outportb(0x3D4, 0xF);
    outportb(0x3D5, temp);
So everytime you print a character, you must update the cursor.

The final code would look something like this:

Code: Select all

static void putc(unsigned char c) 
{	
     uint16_t *where = 0xB8000 + (y *80 + x);
     *where = c | (attribute << 8);
   
      x++;
      if(x == 80)
      {
           x = 0;
           y++;
      }
      unsigned int temp = y * 80 + x;

      outportb(0x3D4, 0xE);
      outportb(0x3D5, temp >> 8);
      outportb(0x3D4, 0xF);
      outportb(0x3D5, temp);
}
You'll never need to read the location from the controller because you already have it :)

The code I gave does not handle null character, carriage return, backspace, etc. Here is a better (more complete) version of the same.

Code: Select all

static void putc(unsigned char c) 
{	
	switch(c)
	{
		case '\0': return;
		case '\b':
			if(curPos_x != 0) curPos_x--;
		break;
		
		case ' ':
			curPos_x++;
		break;
		
		case '\t':
			curPos_x = (curPos_x + 8) & ~(8 - 1);
		break;
		
		case '\r':
			curPos_x = 0;
		break;
		
		case '\n':
			curPos_x = 0;
			curPos_y++;
		break;
		
		default:
		{
			if(isprint(c))
			{
				uint16_t *where = vmemptr + (curPos_y * TEXTMODE_MAX_X + curPos_x);
				*where = c | (attribute << 8);
				curPos_x++;
			}
			break;
		}
	}	
	if(curPos_x >= TEXTMODE_MAX_X)
    {
        curPos_x = 0;
        curPos_y++;
    }	
    if(curPos_y >= TEXTMODE_MAX_Y)
    {
		uint16_t blank = 0x20 | (attribute << 8);
        uint16_t temp = curPos_y - TEXTMODE_MAX_Y + 1;
        memcpy (vmemptr, vmemptr + temp * TEXTMODE_MAX_X, (TEXTMODE_MAX_Y - temp) * TEXTMODE_MAX_X * 2);
        memsetw (vmemptr + (TEXTMODE_MAX_Y - temp) * TEXTMODE_MAX_X, blank, TEXTMODE_MAX_X);
        curPos_y = TEXTMODE_MAX_Y - 1;
    }
	updatecursor();
}
When you are printing strings, you should update the cursor only once. Not every time you print a character. So instead of having update cursor in putc, add it in your puts.
I already created my own functions, i only need that character to not appear.

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 7:14 am
by iansjack
You are printing the release scancode. As you haven't allowed for this it is printing a random character, which happens to be blank.

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 7:28 am
by DixiumOS
iansjack wrote:You are printing the release scancode. As you haven't allowed for this it is printing a random character, which happens to be blank.
I know that, but I don't know what the release scancode is (it's neither 0x80 or 0x81).

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 7:30 am
by iansjack

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 7:38 am
by DixiumOS
If you mean the characters above 0x80, this does not work (scancode < 0x80 doesn't work).

Re: How do i read/get the cursor position?

Posted: Sun Jan 15, 2017 8:31 am
by glauxosdever
Hi,

iansjack wrote:I've been following your train-wreck on #osdev. You don't listen so there is little point in anyone wasting their time to help you.
And not only that, he is ungrateful we try to help him. He even went and spammed the channel.

I've decided to stop trying to help him anymore - he clearly needs to mature first.


Regards,
glauxosdever