How do i read/get the cursor position?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
DixiumOS
Member
Member
Posts: 84
Joined: Tue Jan 10, 2017 3:19 pm
Libera.chat IRC: NunoLava1998

How do i read/get the cursor position?

Post 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?
(not so frequently updated) Code is at:

https://github.com/NunoLava1998/DixiumOS-1
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

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

Post by iansjack »

User avatar
DixiumOS
Member
Member
Posts: 84
Joined: Tue Jan 10, 2017 3:19 pm
Libera.chat IRC: NunoLava1998

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

Post 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.
(not so frequently updated) Code is at:

https://github.com/NunoLava1998/DixiumOS-1
User avatar
matt11235
Member
Member
Posts: 286
Joined: Tue Aug 02, 2016 1:52 pm
Location: East Riding of Yorkshire, UK

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

Post by matt11235 »

Why do you need to get it again? Why not just store the position of the cursor in your code?
com.sun.java.swing.plaf.nimbus.InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState
Compiler Development Forum
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

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

Post 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.
User avatar
DixiumOS
Member
Member
Posts: 84
Joined: Tue Jan 10, 2017 3:19 pm
Libera.chat IRC: NunoLava1998

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

Post 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.
(not so frequently updated) Code is at:

https://github.com/NunoLava1998/DixiumOS-1
TheDev100
Member
Member
Posts: 27
Joined: Wed Jan 11, 2017 3:29 pm

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

Post 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.
User avatar
DixiumOS
Member
Member
Posts: 84
Joined: Tue Jan 10, 2017 3:19 pm
Libera.chat IRC: NunoLava1998

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

Post 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++.
(not so frequently updated) Code is at:

https://github.com/NunoLava1998/DixiumOS-1
ThinkingMind
Posts: 1
Joined: Thu Jan 05, 2017 12:20 pm
Libera.chat IRC: ThinkingMind

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

Post 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.
Last edited by ThinkingMind on Sun Jan 15, 2017 7:14 am, edited 1 time in total.
User avatar
DixiumOS
Member
Member
Posts: 84
Joined: Tue Jan 10, 2017 3:19 pm
Libera.chat IRC: NunoLava1998

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

Post 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.
(not so frequently updated) Code is at:

https://github.com/NunoLava1998/DixiumOS-1
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

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

Post 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.
User avatar
DixiumOS
Member
Member
Posts: 84
Joined: Tue Jan 10, 2017 3:19 pm
Libera.chat IRC: NunoLava1998

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

Post 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).
(not so frequently updated) Code is at:

https://github.com/NunoLava1998/DixiumOS-1
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

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

Post by iansjack »

User avatar
DixiumOS
Member
Member
Posts: 84
Joined: Tue Jan 10, 2017 3:19 pm
Libera.chat IRC: NunoLava1998

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

Post by DixiumOS »

If you mean the characters above 0x80, this does not work (scancode < 0x80 doesn't work).
(not so frequently updated) Code is at:

https://github.com/NunoLava1998/DixiumOS-1
glauxosdever
Member
Member
Posts: 501
Joined: Wed Jun 17, 2015 9:40 am
Libera.chat IRC: glauxosdever
Location: Athens, Greece

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

Post 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
Post Reply