INT 33h AX=0003h is the polling interface to the mouse: it returns the pointer's position and the buttons held down at this moment. It does not wait and does not consume anything, so a program calls it once per frame and acts on the answer.

RegisterReturns
CXx, 0..639 for most modes (0..638 in steps of 2 in mode 13h)
DXy, 0..199 in 80×25 text and the 200-line modes, 0..479 in mode 12h
BX bit 0left button down
BX bit 1right button down
BX bit 2middle button down (three-button mice)

In text mode divide both coordinates by 8 to get the column and row of the character under the pointer; the driver keeps them at multiples of 8 there anyway. The example places the pointer on column 10, row 5, reads it back once and converts:

prints: 80 40 0 -> 10,5 (x, y, buttons, then column and row; move the mouse over the DOS screen while it runs and you may see other numbers)
XOR AX, AX ; reset the driver
INT 33h
MOV AX, 0004h ; put the pointer on column 10, row 5
MOV CX, 10*8 ; x = column x 8
MOV DX, 5*8 ; y = row x 8
INT 33h
MOV AX, 0003h ; read position and buttons, once
INT 33h ; CX = x, DX = y, BX = buttons
MOV SI, CX ; keep them: printing uses DX
MOV DI, DX
MOV AX, SI
CALL PDEC ; x: 80
MOV DL, " "
MOV AH, 02h ; DOS: print the character in DL
INT 21h
MOV AX, DI
CALL PDEC ; y: 40
MOV DL, " "
MOV AH, 02h ; DOS: print the character in DL
INT 21h
MOV AX, BX
AND AX, 0007h ; the three button bits
CALL PDEC ; 0: nothing pressed
MOV DX, OFFSET ARROW1
MOV AH, 09h ; DOS: print the $-string at DS:DX
INT 21h
MOV CL, 3
MOV AX, SI
SHR AX, CL ; column = x / 8
CALL PDEC ; 10
MOV DL, ","
MOV AH, 02h ; DOS: print the character in DL
INT 21h
MOV AX, DI
SHR AX, CL ; row = y / 8
CALL PDEC ; 5
ARROW1 DB " -> $"
PDEC PROC NEAR ; print AX in decimal; keeps every register
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV BX, 10
XOR CX, CX ; digits on the stack
DECD1:
XOR DX, DX
DIV BX ; AX = AX / 10, DX = the last digit
PUSH DX
INC CX
TEST AX, AX
JNZ DECD1
DECD2:
POP DX ; the digits come back first to last
ADD DL, "0"
MOV AH, 02h
INT 21h
LOOP DECD2
POP DX
POP CX
POP BX
POP AX
RET
PDEC ENDP

Clicks

BX is the state now, not a history. A click shorter than the time between two polls is missed entirely, and a button held down is seen as "pressed" on every poll. To react once per click, remember the previous BX and act when a bit goes from 0 to 1. To catch clicks that happen between polls, use AX=0005h (presses since the last call, with the position of the last one) or an event handler, INT 33h AX=000Ch.

MOV AX, 0003h
INT 33h
MOV AX, BX
XOR AX, OLDB1 ; bits that changed since the last poll
AND AX, BX ; ...and are down now: fresh presses
MOV OLDB1, BX
TEST AL, 1 ; the left button went down
JNZ CLICK1

Upper bits of BX are not always zero: drivers with wheel support (CuteMouse, DOSBox-X) put the wheel movement in BH. Mask with AND BX, 7 before comparing.