Skip to main content

Input

One of the most important parts of using an operating system is being able to interact with it. TempleOS lets you access the mouse and keyboard. So let's get started!

Mouse Input

In TempleOS events are typeically accessed via the messaging mechanism. We can get the mouse coordnates by the GetMsg function while looking for MSG_MS_MOVE. You can check for a mouse click via MSG_MS_R_DOWN or MSG_MS_R_DOWN.

I64 x,y;
U0 DrawIt(CTask *t,CDC *dc) {
dc->color=RED;
GrRect(dc,x,y,100,100);
}
U0 Run() {
Fs->draw_it=&DrawIt;
I64 m,x2,y2;
while(TRUE) {
//Here we write into the memory address containing x2/y2 by getting
// the addresses of x2/y2 and GetMsg with write into the these addresses
// chaning their values
m=GetMsg(&x2,&y2,1<<MSG_MS_MOVE+1<<MSG_MS_R_DOWN);
if(m==MSG_MS_R_DOWN)
break;
x=x2;
y=y2;
Refresh;
}
}
Run;

Keyboard Input(1)

You can get keys much like mouse events in TempleOS using GetMsg. But before we dive into this we need to know how keys are transmitted. There are

  • Charactors(letters/numbers/etc) and
  • Scancodes(the raw keycode with modifier keys like Ctrl/Alt)

A charactor is typically what can get displayed on the screen,but scancodes are the juicy stuff. If you press A, the charactor will be 'A',but the scancode will be the raw key code in the .u8 from your keyboard AND some flags.(You can turn a charactor into a scancode via Char2ScanCode('A');)

The flags here will tell you if you were holding down ALT,CTRL,SHIFT or other fun buttons while you pressed. You can check for these flags with the & operator.

A simple example looks like this

I64 x,y;
I64 color=GREEN;
U0 DrawIt(CTask*,CDC*dc) {
dc->color=color;
GrRect(dc,x,y,100,100);
dc->color=RED;
}
U0 Run() {
Fs->draw_it=&DrawIt;
I64 msg,sc,ch;
for(;TRUE;) {
if(ScanMsg(&ch,&sc,1<<MSG_KEY_UP|1<<MSG_KEY_DOWN)) {
//SCAN IS STORED IN FIRST 8 BITS OF sc
if(sc.u8[0]==SC_ESC) break;
if(sc.u8[0]==SC_CURSOR_UP) {
y-=3;
} else if(sc.u8[0]==SC_CURSOR_DOWN) {
y+=3;
} else if(sc.u8[0]==SC_CURSOR_LEFT) {
x-=3;
} else if(sc.u8[0]==SC_CURSOR_RIGHT) {
x+=3;
}
//WE USE THE & OPERATOR TO TEST IF THE FLAG BIT IS SET OR NOT
if(sc&SCF_CTRL)
color=RED;
else if(sc&SCF_SHIFT)
color=YELLOW;
else
color=GREEN;
} else {
//Wait for a frame to be rendered
Refresh;
}
}
}
Run;

Keyboard Input(2) Scancode Galore

Scancodes have a rigid format. Each byte in a scancdoe has a specific purpose. The first byte is the most important and can be accessed via scancode.u8[0].

ByteMeaning
0Scancode (SC_ESC,SC_CURSOR_LEFT)
1 through 3Flags
4 Repeat of byte 0
5 through 7Repeat of bytes 1-3

The flags are plentiful and contain a bitmask. You can test for a flag by bitwise ANDing with the scancode to test the bit is set(no need to use scancode.u8[xxx])

FlagMeaning
SCF_KEY_UPThe key is being released
SCF_SHIFTThe shift key is down.
SCFCTRLThe control key is down.
SCF_ALTThe alt key is down.
SCF_CAPSThe caps key is active.
SCF_NUMThe numlock key is active.
SCF_SCROLLThe scrolllock key is active.
SCF_MS_L_DOWNMouse left button is down.
SCF_MS_R_DOWNMouse left button is down.
SCF_NO_SHIFTShift is not active.

Keyboard Input(3)Multiple keys at once

Sometimes you want to check if multiple keys are down at once. Luckily for you TempleOS keeps a record of all down keys. It is a bitfield called kbd.down_bitmap. Each scancode is a bit and can tested via Bt(kbd.down_bitmap,scancode)... Example time:

I64 x,y;
U0 DrawIt(CTask*,CDC*dc) {
dc->color=GREEN;
GrRect(dc,x,y,100,100);
}
U0 Run() {
Fs->draw_it=&DrawIt;
I64 msg,sc,ch;
for(;TRUE;) {
if(Bt(kbd.down_bitmap,SC_ESC)) break;
if(Bt(kbd.down_bitmap,SC_CURSOR_UP)) y-=3;
if(Bt(kbd.down_bitmap,SC_CURSOR_DOWN)) y+=3;
if(Bt(kbd.down_bitmap,SC_CURSOR_LEFT)) x-=3;
if(Bt(kbd.down_bitmap,SC_CURSOR_RIGHT)) x+=3;
//Wait for a frame to be rendered
Refresh;
}
}
Run;
Exit;