;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
;; Distributed under terms of the GNU General Public License    ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

$Revision$


VKEY_LSHIFT   = 0000000000000001b
VKEY_RSHIFT   = 0000000000000010b
VKEY_LCONTROL = 0000000000000100b
VKEY_RCONTROL = 0000000000001000b
VKEY_LALT     = 0000000000010000b
VKEY_RALT     = 0000000000100000b
VKEY_CAPSLOCK = 0000000001000000b
VKEY_NUMLOCK  = 0000000010000000b
VKEY_SCRLOCK  = 0000000100000000b
VKEY_LWIN     = 0000001000000000b
VKEY_RWIN     = 0000010000000000b

VKEY_SHIFT    = 0000000000000011b
VKEY_CONTROL  = 0000000000001100b
VKEY_ALT      = 0000000000110000b

uglobal
  ext_code      db 0

  keyboard_mode db 0
  keyboard_data db 0

  altmouseb     db 0
  ctrl_alt_del  db 0

  old_kb_lights db 0

align 4
        hotkey_scancodes        rd      256     ; we have 256 scancodes
        hotkey_list             rd      256*4   ; max 256 defined hotkeys
        hotkey_buffer           rd      120*2   ; buffer for 120 hotkeys
endg

iglobal
  kb_lights     db 2
  align 4
  kb_state      dd VKEY_NUMLOCK
endg

iglobal
align 4
hotkey_tests    dd      hotkey_test0
                dd      hotkey_test1
                dd      hotkey_test2
                dd      hotkey_test3
                dd      hotkey_test4
hotkey_tests_num = 5
endg
;---------------------------------------------------------------------
hotkey_test0:
        test    al, al
        setz    al
        ret
;---------------------------------------------------------------------
hotkey_test1:
        test    al, al
        setnp   al
        ret
;---------------------------------------------------------------------
hotkey_test2:
        cmp     al, 3
        setz    al
        ret
;---------------------------------------------------------------------
hotkey_test3:
        cmp     al, 1
        setz    al
        ret
;---------------------------------------------------------------------
hotkey_test4:
        cmp     al, 2
        setz    al
        ret
;---------------------------------------------------------------------
hotkey_do_test:
        push    eax
        mov     edx, [kb_state]
        shr     edx, cl
        add     cl, cl
        mov     eax, [eax+4]
        shr     eax, cl
        and     eax, 15
        cmp     al, hotkey_tests_num
        jae     .fail
        
        xchg    eax, edx
        and     al, 3
        call    [hotkey_tests + edx*4]
        cmp     al, 1
        pop     eax
        ret
;--------------------------------------
.fail:
        stc
        pop     eax
        ret
;---------------------------------------------------------------------
align 4
set_keyboard_data:
        movzx   eax, word[TASK_COUNT]; top window process
        movzx   eax, word[WIN_POS+eax*2]
        shl     eax, 8
        mov     al, [SLOT_BASE+eax+APPDATA.keyboard_mode]
        mov     [keyboard_mode], al
        
        mov     eax, ecx
        
        push    ebx esi edi ebp
        call    send_scancode
        pop     ebp edi esi ebx
        ret
;---------------------------------------------------------------------
struct KEYBOARD
next           dd      ?
prev           dd      ?
functions      dd      ?
userdata       dd      ?
ends
struct KBDFUNC
strucsize      dd      ?
close          dd      ?
setlights      dd      ?
ends

iglobal
keyboards:
        dd      keyboards
        dd      keyboards
endg
uglobal
keyboard_list_mutex     MUTEX
endg

register_keyboard:
        push    ebx
        movi    eax, sizeof.KEYBOARD
        call    malloc
        test    eax, eax
        jz      .nothing
        mov     ecx, [esp+4+4]
        mov     [eax+KEYBOARD.functions], ecx
        mov     ecx, [esp+8+4]
        mov     [eax+KEYBOARD.userdata], ecx
        xchg    eax, ebx
        mov     ecx, keyboard_list_mutex
        call    mutex_lock
        mov     ecx, keyboards
        mov     edx, [ecx+KEYBOARD.prev]
        mov     [ebx+KEYBOARD.next], ecx
        mov     [ebx+KEYBOARD.prev], edx
        mov     [edx+KEYBOARD.next], ebx
        mov     [ecx+KEYBOARD.prev], ebx
        mov     ecx, [ebx+KEYBOARD.functions]
        cmp     [ecx+KBDFUNC.strucsize], KBDFUNC.setlights
        jbe     .unlock
        mov     ecx, [ecx+KBDFUNC.setlights]
        test    ecx, ecx
        jz      .unlock
        stdcall ecx, [ebx+KEYBOARD.userdata], dword [kb_lights]
.unlock:
        mov     ecx, keyboard_list_mutex
        call    mutex_unlock
        xchg    eax, ebx
.nothing:
        pop     ebx
        ret     8

delete_keyboard:
        push    ebx
        mov     ebx, [esp+4+4]
        mov     ecx, keyboard_list_mutex
        call    mutex_lock
        mov     eax, [ebx+KEYBOARD.next]
        mov     edx, [ebx+KEYBOARD.prev]
        mov     [eax+KEYBOARD.prev], edx
        mov     [edx+KEYBOARD.next], eax
        call    mutex_unlock
        mov     ecx, [ebx+KEYBOARD.functions]
        cmp     [ecx+KBDFUNC.strucsize], KBDFUNC.close
        jbe     .nothing
        mov     ecx, [ecx+KBDFUNC.close]
        test    ecx, ecx
        jz      .nothing
        stdcall ecx, [ebx+KEYBOARD.userdata]
.nothing:
        pop     ebx
        ret     4
;---------------------------------------------------------------------
align 4
irq1:
        movzx   eax, word[TASK_COUNT]; top window process
        movzx   eax, word[WIN_POS+eax*2]
        shl     eax, 8
        mov     al, [SLOT_BASE+eax+APPDATA.keyboard_mode]
        mov     [keyboard_mode], al
        
        in      al, 0x60
;--------------------------------------
send_scancode:
        mov     [keyboard_data], al
; ch = scancode
; cl = ext_code
; bh = 0 - normal key
; bh = 1 - modifier (Shift/Ctrl/Alt)
; bh = 2 - extended code
        mov     ch, al
        cmp     al, 0xE0
        je      @f
        
        cmp     al, 0xE1
        jne     .normal_code
@@:
        mov     bh, 2
        mov     [ext_code], al
        jmp     .writekey
;--------------------------------------
.normal_code:
        mov     cl, 0
        xchg    cl, [ext_code]
        and     al, 0x7F
        mov     bh, 1
;--------------------------------------
@@:
        cmp     al, 0x5B
        jne     @f
        
        cmp     cl, 0xE0
        jne     @f
        
        mov     eax, VKEY_LWIN
        mov     bh, 0
        jmp     .modifier
;--------------------------------------
@@:
        cmp     al, 0x5C
        jne     @f
        
        cmp     cl, 0xE0
        jne     @f
        
        mov     eax, VKEY_RWIN
        mov     bh, 0
        jmp     .modifier
;--------------------------------------
@@:
        cmp     al, 0x2A
        jne     @f
        
        cmp     cl, 0xE0
        je      .writekey
        
        mov     eax, VKEY_LSHIFT
        jmp     .modifier
;--------------------------------------
@@:
        cmp     al, 0x36
        jne     @f
        
        cmp     cl, 0xE0
        je      .writekey
        
        mov     eax, VKEY_RSHIFT
        jmp     .modifier
;--------------------------------------
@@:
        cmp     al, 0x38
        jne     @f
        
        mov     eax, VKEY_LALT
        test    cl, cl
        jz      .modifier
        
        mov     al, VKEY_RALT
        jmp     .modifier
;--------------------------------------
@@:
        cmp     al, 0x1D
        jne     @f
        
        mov     eax, VKEY_LCONTROL
        test    cl, cl
        jz      .modifier
        
        mov     al, VKEY_RCONTROL
        cmp     cl, 0xE0
        jz      .modifier
        
        mov     [ext_code], cl
        jmp     .writekey
;--------------------------------------
@@:
        cmp     al, 0x3A
        jne     @f
        
        mov     bl, 4
        mov     eax, VKEY_CAPSLOCK
        jmp     .no_key.xor
;--------------------------------------
@@:
        cmp     al, 0x45
        jne     @f
        test    cl, cl
        jnz     .writekey
        
        mov     bl, 2
        mov     eax, VKEY_NUMLOCK
        jmp     .no_key.xor
;--------------------------------------
@@:
        cmp     al, 0x46
        jne     @f
        
        mov     bl, 1
        mov     eax, VKEY_SCRLOCK
        jmp     .no_key.xor
;--------------------------------------
@@:
        xor     ebx, ebx
        test    ch, ch
        js      .writekey
        
        movzx   eax, ch          ; plain key
        mov     bl, [keymap+eax]
        mov     edx, [kb_state]
        test    dl, VKEY_CONTROL ; ctrl alt del
        jz      .noctrlaltdel
        
        test    dl, VKEY_ALT
        jz      .noctrlaltdel
        
        cmp     ch, 53h
        jne     .noctrlaltdel
        
        mov     [ctrl_alt_del], 1
        call    wakeup_osloop
.noctrlaltdel:
        test    dl, VKEY_CONTROL ; ctrl on ?
        jz      @f
        
        sub     bl, 0x60
@@:
        test    dl, VKEY_CAPSLOCK        ; caps lock on ?
        jz      .no_caps_lock
        
        test    dl, VKEY_SHIFT   ; shift on ?
        jz      .keymap_shif
        
        jmp     @f
;--------------------------------------
.no_caps_lock:
        test    dl, VKEY_SHIFT   ; shift on ?
        jz      @f
.keymap_shif:   
        mov     bl, [keymap_shift+eax]
@@:
        test    dl, VKEY_ALT     ; alt on ?
        jz      @f
        
        mov     bl, [keymap_alt+eax]
@@:
        jmp     .writekey
;--------------------------------------
.modifier:
        test    ch, ch
        js      .modifier.up
        or      [kb_state], eax
        jmp     .writekey
;--------------------------------------
.modifier.up:
        not     eax
        and     [kb_state], eax
        jmp     .writekey
;--------------------------------------
.no_key.xor:
        mov     bh, 0
        test    ch, ch
        js      .writekey
        
        xor     [kb_state], eax
        xor     [kb_lights], bl
.writekey:
        pushad
; test for system hotkeys
        movzx   eax, ch
        cmp     bh, 1
        ja      .nohotkey
        jb      @f
        
        xor     eax, eax
@@:
        mov     eax, [hotkey_scancodes + eax*4]
.hotkey_loop:
        test    eax, eax
        jz      .nohotkey
        
        mov     cl, 0
        call    hotkey_do_test
        jc      .hotkey_cont
        
        mov     cl, 2
        call    hotkey_do_test
        jc      .hotkey_cont
        
        mov     cl, 4
        call    hotkey_do_test
        jnc     .hotkey_found
.hotkey_cont:
        mov     eax, [eax]
        jmp     .hotkey_loop
;--------------------------------------
.hotkey_found:
        mov     eax, [eax+8]
; put key in buffer for process in slot eax
        mov     edi, hotkey_buffer
@@:
        cmp     dword [edi], 0
        jz      .found_free
        
        add     edi, 8
        cmp     edi, hotkey_buffer+120*8
        jb      @b
; no free space - replace first entry
        mov     edi, hotkey_buffer
.found_free:
        mov     [edi], eax
        movzx   eax, ch
        cmp     bh, 1
        jnz     @f
        
        xor     eax, eax
@@:
        mov     [edi+4], ax
        mov     eax, [kb_state]
        mov     [edi+6], ax

        cmp     [PID_lock_input], dword 0
        je      .nohotkey

        popad
        jmp     .exit.irq1
;--------------------------------------
.nohotkey:
        popad

        cmp     [keyboard_mode], 0; return from keymap
        jne     .scancode
        
        test    bh, bh
        jnz     .exit.irq1
        
        test    bl, bl
        jz      .exit.irq1

        cmp     cl, 0xE0        ; extended keycode
        jne     @f

        cmp     ch, 53
        jne     .dowrite
        
        mov     bl, '/'
        jmp     .dowrite
@@:
        
        cmp     ch, 55
        jne     @f
        
        mov     bl, '*'
        jmp     .dowrite
@@:

        cmp     ch, 74
        jne     @f
        
        mov     bl, '-'
        jmp     .dowrite
@@:

        cmp     ch, 78
        jne     @f
        
        mov     bl, '+'
        jmp     .dowrite
@@:

        test    [kb_state], VKEY_NUMLOCK
        jz      .dowrite

        cmp     ch, 71
        jb      .dowrite
        
        cmp     ch, 83
        ja      .dowrite
        
        movzx   eax, ch
        mov     bl, [numlock_map + eax - 71]
        jmp     .dowrite
;--------------------------------------
.scancode:
        mov     bl, ch
.dowrite:
        movzx   eax, byte[KEY_COUNT]
        cmp     al, 120
        jae     .exit.irq1
        inc     eax
        mov     [KEY_COUNT], al
; store ascii or scancode
        mov     [KEY_COUNT+eax], bl ; actually KEY_BUFF + EAX - 1
; store original scancode
        add     eax, 120+2
        push    ecx
        cmp     [keyboard_mode], 0; return from keymap
        je      @f

        xor     ch, ch
@@:
        mov     [KEY_COUNT+eax], ch ; actually KEY_BUFF + EAX - 1
        pop     ecx
        sub     eax, 120+2
.exit.irq1:
        ret
;---------------------------------------------------------------------
set_lights:
        push    ebx esi
        mov     ecx, keyboard_list_mutex
        call    mutex_lock
        mov     esi, keyboards
.loop:
        mov     esi, [esi+KEYBOARD.next]
        cmp     esi, keyboards
        jz      .done
        mov     eax, [esi+KEYBOARD.functions]
        cmp     dword [eax], KBDFUNC.setlights
        jbe     .loop
        mov     eax, [eax+KBDFUNC.setlights]
        test    eax, eax
        jz      .loop
        stdcall eax, [esi+KEYBOARD.userdata], dword [kb_lights]
        jmp     .loop
.done:
        mov     ecx, keyboard_list_mutex
        call    mutex_unlock
        pop     esi ebx
        ret

ps2_set_lights:
        stdcall disable_irq, 1
        mov     al, 0xED
        call    kb_write_wait_ack
        mov     al, [esp+8]
        call    kb_write_wait_ack
        stdcall enable_irq, 1
        ret     8

;// mike.dld ]
proc check_lights_state_has_work?
        mov     al, [kb_lights]
        cmp     al, [old_kb_lights]
        ret
endp

check_lights_state:
        call    check_lights_state_has_work?
        jz      .nothing
        mov     [old_kb_lights], al
        call    set_lights
.nothing:
        ret
;---------------------------------------------------------------------
numlock_map:
    db   0x37   ;Num 7
    db   0x38   ;Num 8
    db   0x39   ;Num 9
    db   0x2D   ;Num -
    db   0x34   ;Num 4
    db   0x35   ;Num 5
    db   0x36   ;Num 6
    db   0x2B   ;Num +
    db   0x31   ;Num 1
    db   0x32   ;Num 2
    db   0x33   ;Num 3
    db   0x30   ;Num 0
    db   0x2E   ;Num .
;---------------------------------------------------------------------