MODULE UsbKeyboard;
IMPORT SYSTEM, Machine, Files, Inputs, Commands, KernelLog, Streams, Plugins, Modules, Usb, Usbdi, UsbHid;
CONST
Name = "UsbKeyboard";
Description = "USB Keyboard Driver";
Priority = 10;
NumLock* = 0;
CapsLock* = 1;
ScrollLock* = 2;
Compose = 3;
Kana = 4;
KeyDeadTime* = 100;
KeyDeadTimeRepeat* = 0;
TraceKeys* = FALSE;
Debug* = TRUE;
TYPE
Key* = RECORD
ch* : CHAR;
keysym* : LONGINT;
counter* : LONGINT;
repeat* : BOOLEAN;
updated* : BOOLEAN;
END;
TYPE
KeyboardBase*=OBJECT
VAR
msg*, lastMsg : Inputs.KeyboardMsg;
lastFlags : SET;
numKeyVal : LONGINT;
deadKey* : LONGINT;
dkHack* : LONGINT;
leds*, lastLeds* : SET;
ledBuffer* : Usbdi.BufferPtr;
keyboardFileTable : POINTER TO ARRAY OF CHAR;
keytable* : SYSTEM.ADDRESS;
keyDeadTime*, keyDeadTimeRepeat* : LONGINT;
PROCEDURE HandleKey*(c : CHAR);
VAR k : LONGINT;
BEGIN
msg.keysym := KeySym(c, leds);
IF TraceKeys THEN KernelLog.String("USB Usage ID: "); KernelLog.Hex(ORD(c), -3); END;
SYSTEM.GET(UsbScanTab() + ORD(c), c);
IF TraceKeys THEN KernelLog.String(" -> Oberon key code: "); KernelLog.Hex(ORD(c), -3) END;
IF c = CHR(58) THEN leds := leds / {CapsLock};
ELSIF c = CHR(69) THEN leds := leds / {NumLock};
ELSIF c = CHR(70) THEN leds := leds / {ScrollLock};
ELSE
k := Translate(msg.flags, leds, c, keytable, deadKey, numKeyVal);
IF TraceKeys THEN KernelLog.String(" translated into: "); KernelLog.Char(CHR(k)); END;
IF (k >= 1) & (k <= 126) & (msg.keysym = Inputs.KsNil) THEN msg.keysym := k; END;
IF k >= 0 THEN msg.ch := CHR(k) ELSE msg.ch := 0X END;
IF TraceKeys THEN
KernelLog.String(" Aos Keysym: "); IF msg.keysym = Inputs.KsNil THEN KernelLog.String("No Key"); ELSE KernelLog.Hex(msg.keysym, 9); END;
KernelLog.Ln; ShowFlags(msg.flags, leds); KernelLog.Ln;
END;
IF (msg.flags # lastMsg.flags) OR (msg.ch # 0X) OR (msg.keysym # Inputs.KsNil) THEN
Inputs.keyboard.Handle(msg);
END;
lastMsg := msg;
END;
END HandleKey;
PROCEDURE HandleModifiers*(flags : SET);
VAR i : LONGINT;
BEGIN
IF flags # lastFlags THEN
msg.flags := {}; msg.ch := 0X; msg.keysym := Inputs.KsNil;
FOR i := 0 TO MAX(SET) DO
IF (i IN flags) & ~(i IN lastFlags) THEN
msg.flags := {i}; msg.keysym := GetModifierKeysym(i);
Inputs.keyboard.Handle(msg);
ELSIF ~(i IN flags) & (i IN lastFlags) THEN
msg.flags := {Inputs.Release}; msg.keysym := GetModifierKeysym(i);
Inputs.keyboard.Handle(msg);
END;
END;
END;
lastFlags := flags;
END HandleModifiers;
PROCEDURE TableFromFile*(CONST name: ARRAY OF CHAR): SYSTEM.ADDRESS;
VAR f: Files.File; r: Files.Rider; len: LONGINT;
BEGIN
KernelLog.String("UsbKeyboard: "); KernelLog.String(" Loading layout "); KernelLog.String(name); KernelLog.Ln;
f := Files.Old(name);
IF f # NIL THEN
len := f.Length();
IF len MOD 4 = 0 THEN
NEW(keyboardFileTable, len+1);
f.Set(r, 0); f.ReadBytes(r, keyboardFileTable^, 0, len);
IF r.res = 0 THEN
keyboardFileTable[len] := 0FFX;
RETURN SYSTEM.ADR(keyboardFileTable[0])
ELSIF Debug THEN KernelLog.String("UsbKeyboard: TableFromFile: Error: res="); KernelLog.Int(r.res, 1); KernelLog.Ln;
END
ELSIF Debug THEN KernelLog.String("UsbKeyboard: TableFromFile: Error: len="); KernelLog.Int(len, 1); KernelLog.Ln;
END
ELSIF Debug THEN KernelLog.String("UsbKeyboard: TableFromFile: Error: File not found."); KernelLog.Ln;
END;
RETURN -1;
END TableFromFile;
PROCEDURE SetLayout*(CONST name : ARRAY OF CHAR);
VAR adr : SYSTEM.ADDRESS;
BEGIN
IF name = "KeyUS.Bin" THEN adr := TableUS();
ELSE adr := TableFromFile(name);
END;
IF adr = -1 THEN
ELSE SYSTEM.PUT(SYSTEM.ADR(keytable), adr);
END;
END SetLayout;
END KeyboardBase;
KeyboardDriver = OBJECT (UsbHid.HidDriver)
VAR
pipe : Usbdi.Pipe;
buffer : Usbdi.BufferPtr;
base : KeyboardBase;
pressed* : ARRAY 6 OF Key;
PROCEDURE &Init*;
BEGIN
NEW(base);
END Init;
PROCEDURE EventHandler(status : Usbdi.Status; actLen : LONGINT);
VAR
i, j : LONGINT;
c : CHAR;
modifiers, flags : SET;
res : BOOLEAN;
tempPressed : ARRAY 6 OF Key;
found, kill : BOOLEAN;
BEGIN
IF (status=Usbdi.Ok) OR ((status = Usbdi.ShortPacket) & (actLen >= 8)) THEN
base.msg.flags := {};
modifiers := SYSTEM.VAL(SET, buffer[0]);
IF modifiers * {0} # {} THEN INCL(base.msg.flags, Inputs.LeftCtrl) END;
IF modifiers * {1} # {} THEN INCL(base.msg.flags, Inputs.LeftShift) END;
IF modifiers * {2} # {} THEN INCL(base.msg.flags, Inputs.LeftAlt) END;
IF modifiers * {3} # {} THEN INCL(base.msg.flags, Inputs.LeftMeta) END;
IF modifiers * {4} # {} THEN INCL(base.msg.flags, Inputs.RightCtrl) END;
IF modifiers * {5} # {} THEN INCL(base.msg.flags, Inputs.RightShift) END;
IF modifiers * {6} # {} THEN INCL(base.msg.flags, Inputs.RightAlt) END;
IF modifiers * {7} # {} THEN INCL(base.msg.flags, Inputs.RightMeta) END;
flags := base.msg.flags;
FOR i := 2 TO 7 DO
c := buffer[i];
IF c # CHR(0) THEN
FOR j := 0 TO 5 DO
IF pressed[j].ch = c THEN
found := TRUE;
pressed[j].updated := TRUE;
tempPressed[i-2].counter := pressed[j].counter + 1;
tempPressed[i-2].ch := pressed[j].ch;
tempPressed[i-2].keysym := pressed[j].keysym;
tempPressed[i-2].updated := FALSE;
tempPressed[i-2].repeat := pressed[j].repeat;
IF pressed[j].repeat THEN
IF (base.keyDeadTimeRepeat # 0) & (tempPressed[i-2].counter MOD base.keyDeadTimeRepeat # 0) THEN kill := TRUE; END;
ELSE
IF tempPressed[i-2].counter MOD base.keyDeadTime # 0 THEN
kill := TRUE;
ELSE
tempPressed[i-2].repeat := TRUE;
END;
END;
END;
END;
END;
IF ~found THEN
tempPressed[i-2].ch := c;
tempPressed[i-2].repeat := FALSE;
tempPressed[i-2].updated := FALSE;
tempPressed[i-2].counter := 1;
END;
IF (c # CHR(0)) & ~kill THEN
base.HandleKey(c);
tempPressed[i-2].keysym := base.msg.keysym;
END;
END;
FOR i := 0 TO 5 DO
IF (pressed[i].updated = FALSE) & (pressed[i].ch # CHR(0)) THEN
base.msg.flags := {};
INCL(base.msg.flags, Inputs.Release);
base.msg.ch := pressed[i].ch;
base.msg.keysym := pressed[i].keysym;
base.dkHack := base.deadKey;
base.HandleKey(c);
base.deadKey := base.dkHack;
END;
pressed[i].counter := tempPressed[i].counter;
pressed[i].ch := tempPressed[i].ch;
pressed[i].keysym := tempPressed[i].keysym;
pressed[i].repeat := tempPressed[i].repeat;
pressed[i].updated := FALSE;
END;
base.HandleModifiers(flags);
IF base.lastLeds # base.leds THEN
base.ledBuffer[0] := SYSTEM.VAL(CHAR, base.leds); base.lastLeds := base.leds;
res := SetReport(UsbHid.ReportOutput, 0, base.ledBuffer^, 1);
END;
status := pipe.Transfer(pipe.maxPacketSize, 0, buffer^);
ELSE
IF Debug THEN KernelLog.String("UsbKeyboard: Error. Disabling keyboard "); KernelLog.String(name); KernelLog.Ln; END;
END;
END EventHandler;
PROCEDURE Connect*(): BOOLEAN;
VAR status : Usbdi.Status; endpoint: LONGINT; i: SYSTEM.ADDRESS; k : ARRAY 32 OF CHAR;
BEGIN
IF ~SetProtocol(0) THEN
IF Debug THEN KernelLog.String("UsbKeyboard: Error: Cannot set keyboard into boot protocol mode."); KernelLog.Ln; END;
RETURN FALSE
END;
IF ~SetIdle(0,10) THEN
IF Debug THEN KernelLog.String("UsbKeyboard: Error: Cannot set idle the keyboard."); KernelLog.Ln; END;
RETURN FALSE
END;
endpoint := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, interface.endpoints[0].bEndpointAddress) * {0,1,2,3,7});
pipe := device.GetPipe(endpoint);
IF pipe = NIL THEN
IF Debug THEN KernelLog.String("UsbKeyboard: Could not get pipe."); KernelLog.Ln; END;
RETURN FALSE;
END;
Machine.GetConfig("Keyboard", k);
i := -1;
IF k # "" THEN i := base.TableFromFile(k); END;
IF i = -1 THEN i := TableUS(); END;
SYSTEM.PUT(SYSTEM.ADR(base.keytable), i);
Machine.GetConfig("NumLock", k);
IF k[0] = "1" THEN INCL(base.leds, NumLock) END;
base.keyDeadTime := KeyDeadTime DIV 10;
base.keyDeadTimeRepeat := KeyDeadTimeRepeat DIV 10;
NEW(base.ledBuffer, 1);
NEW(buffer, pipe.maxPacketSize);
pipe.SetTimeout(0);
pipe.SetCompletionHandler(EventHandler);
status := pipe.Transfer(pipe.maxPacketSize, 0, buffer^);
RETURN TRUE;
END Connect;
PROCEDURE Disconnect*;
BEGIN
KernelLog.String("UsbKeyboard: USB Keyboard disconnected."); KernelLog.Ln;
END Disconnect;
END KeyboardDriver;
VAR
PROCEDURE TableUS*(): SYSTEM.ADDRESS;
CODE {SYSTEM.AMD64}
LEA RAX, [RIP + L2 - L1];
L1:
LEAVE
RET
L2:
; alphabet
DB 1EH, 'a', 'A', 4H, 30H, 'b', 'B', 4H, 2EH, 'c', 'C', 4H, 20H, 'd', 'D', 4H
DB 12H, 'e', 'E', 4H, 21H, 'f', 'F', 4H, 22H, 'g', 'G', 4H, 23H, 'h', 'H', 4H
DB 17H, 'i', 'I', 4H, 24H, 'j', 'J', 4H, 25H, 'k', 'K', 4H, 26H, 'l', 'L', 4H
DB 32H, 'm', 'M', 4H, 31H, 'n', 'N', 4H, 18H, 'o', 'O', 4H, 19H, 'p', 'P', 4H
DB 10H, 'q', 'Q', 4H, 13H, 'r', 'R', 4H, 1FH, 's', 'S', 4H, 14H, 't', 'T', 4H
DB 16H, 'u', 'U', 4H, 2FH, 'v', 'V', 4H, 11H, 'w', 'W', 4H, 2DH, 'x', 'X', 4H
DB 15H, 'y', 'Y', 4H, 2CH, 'z', 'Z', 4H
; Oberon accents (LAlt & RAlt)
; DB 1EH, 'ä', 'Ä', 0CH, 12H, 'ë', 0FFH, 0CH, 18H, 'ö', 'Ö', 0CH, 16H, 'ü', 'Ü', 0CH
; DB 17H, 'ï', 0FFH, 0CH, 1FH, 'ß', 0FFH, 0CH, 2EH, 'ç', 0FFH, 0CH, 31H, 'ñ', 0FFH, 0CH
; DB 1EH, 'ä', 'Ä', 14H, 12H, 'ë', 0FFH, 14H, 18H, 'ö', 'Ö', 14H, 16H, 'ü', 'Ü', 14H
; DB 17H, 'ï', 0FFH, 14H, 1FH, 'ß', 0FFH, 14H, 2EH, 'ç', 0FFH, 14H, 31H, 'ñ', 0FFH, 14H
; dead keys (LAlt & RAlt)
DB 07H, 0FFH, 1H, 9H, 28H, 2H, 5H, 9H, 29H, 3H, 4H, 9H,
DB 07H, 0FFH, 1H, 11H, 28H, 2H, 5H, 11H, 29H, 3H, 4H, 11H,
; following keys
; DB 1EH, 'â', 0FFH, 20H, 12H, 'ê', 0FFH, 20H, 17H, 'î', 0FFH, 20H, 18H, 'ô', 0FFH, 20H
; DB 16H, 'û', 0FFH, 20H, 1EH, 'à', 0FFH, 60H, 12H, 'è', 0FFH, 60H, 17H, 'ì', 0FFH, 60H
; DB 18H, 'ò', 0FFH, 60H, 16H, 'ù', 0FFH, 60H, 1EH, 'á', 0FFH, 40H, 12H, 'é', 0FFH, 40H
; DB 1EH, 'ä', 'Ä', 0A4H, 12H, 'ë', 0FFH, 0A0H, 17H, 'ï', 0FFH, 0A0H, 18H, 'ö', 'Ö', 0A4H
; DB 16H, 'ü', 'Ü', 0A4H, 31H, 'ñ', 0FFH, 80H
; numbers at top
DB 0BH, '0', ')', 0H, 02H, '1', '!', 0H, 03H, '2', '@', 0H, 04H, '3', '#', 0H
DB 05H, '4', '$', 0H, 06H, '5', '%', 0H, 07H, '6', '^', 0H, 08H, '7', '&', 0H
DB 09H, '8', '*', 0H, 0AH, '9', '(', 0H
; symbol keys
DB 28H, 27H, 22H, 0H, 33H, ',', '<', 0H, 0CH, '-', '_', 0H, 34H, '.', '>', 0H
DB 35H, '/', '?', 0H, 27H, ';', ':', 0H, 0DH, '=', '+', 0H, 1AH, '[', '{', 0H
DB 2BH, '\', '|', 0H, 1BH, ']', '}', 0H, 29H, '`', '~', 0H
; control keys
DB 0EH, 7FH, 7FH, 0H ; backspace
DB 0FH, 09H, 09H, 0H ; tab
DB 1CH, 0DH, 0DH, 0H ; enter
DB 39H, 20H, 20H, 0H ; space
DB 01H, 0FEH, 1BH, 0H ; esc
; keypad
DB 4FH, 0A9H, '1', 2H ; end/1
DB 50H, 0C2H, '2', 2H ; down/2
DB 51H, 0A3H, '3', 2H ; pgdn/3
DB 4BH, 0C4H, '4', 2H ; left/4
DB 4CH, 0FFH, '5', 2H ; center/5
DB 4DH, 0C3H, '6', 2H ; right/6
DB 47H, 0A8H, '7', 2H ; home/7
DB 48H, 0C1H, '8', 2H ; up/8
DB 49H, 0A2H, '9', 2H ; pgup/9
DB 52H, 0A0H, '0', 2H ; insert/0
DB 53H, 0A1H, 2EH, 2H ; del/.
; gray keys
DB 4AH, '-', '-', 0H ; gray -
DB 4EH, '+', '+', 0H ; gray +
DB 0B5H, '/', '/', 0H ; gray /
DB 37H, '*', '*', 0H ; gray *
DB 0D0H, 0C2H, 0C2H, 0H ; gray down
DB 0CBH, 0C4H, 0C4H, 0H ; gray left
DB 0CDH, 0C3H, 0C3H, 0H ; gray right
DB 0C8H, 0C1H, 0C1H, 0H ; gray up
DB 09CH, 0DH, 0DH, 0H ; gray enter
DB 0D2H, 0A0H, 0A0H, 0H ; gray ins
DB 0D3H, 0A1H, 0A1H, 0H ; gray del
DB 0C9H, 0A2H, 0A2H, 0H ; gray pgup
DB 0D1H, 0A3H, 0A3H, 0H ; gray pgdn
DB 0C7H, 0A8H, 0A8H, 0H ; gray home
DB 0CFH, 0A9H, 0A9H, 0H ; gray end
; function keys
DB 3BH, 0A4H, 0FFH, 0H ; F1
DB 3CH, 0A5H, 0FFH, 0H ; F2
DB 3DH, 1BH, 0FFH, 0H ; F3
DB 3EH, 0A7H, 0FFH, 0H ; F4
DB 3FH, 0F5H, 0FFH, 0H ; F5
DB 40H, 0F6H, 0FFH, 0H ; F6
DB 41H, 0F7H, 0FFH, 0H ; F7
DB 42H, 0F8H, 0FFH, 0H ; F8
DB 43H, 0F9H, 0FFH, 0H ; F9
DB 44H, 0FAH, 0FFH, 0H ; F10
DB 57H, 0FBH, 0FFH, 0H ; F11
DB 58H, 0FCH, 0FFH, 0H ; F12
DB 0FFH
END TableUS;
PROCEDURE UsbScanTab*() : SYSTEM.ADDRESS;
CODE {SYSTEM.AMD64}
LEA RAX, [RIP + L2 - L1];
L1:
LEAVE
RET
L2:
; Keyboard table stolen from Linux Usb keyboard driver, and corrected for Oberon
DB 000, 000, 000, 000, 030, 048, 046, 032, 018, 033, 034, 035, 023, 036, 037, 038
DB 050, 049, 024, 025, 016, 019, 031, 020, 022, 047, 017, 045, 021 ,044, 002, 003
DB 004, 005, 006, 007, 008, 009, 010, 011, 028, 001, 014, 015 ,057, 012, 013, 026
DB 027, 043, 043, 039, 040, 041, 051, 052, 053, 058, 059, 060, 061, 062, 063, 064
DB 065, 066, 067, 068, 087, 088, 099, 070, 119, 210, 199, 201, 211, 207, 209, 205
DB 203, 208, 200, 069, 181, 055, 074, 078, 156, 079, 080, 081, 075, 076, 077, 071
DB 072, 073, 082, 083, 086, 127, 116, 117, 085, 089, 090, 091, 092, 093, 094, 095
DB 120, 121, 122, 123, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, 136, 113
DB 115, 114, 000, 000, 000, 000, 000, 124, 000, 000, 000, 000, 000, 000, 000, 000
DB 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000
DB 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000
DB 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000
DB 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000
DB 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000
DB 029, 042, 056, 125, 097, 054, 100, 126, 164, 166, 165, 163, 161, 115, 114, 113
DB 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140, 000, 000, 000, 000
END UsbScanTab;
PROCEDURE KeySym*(VAR ch : CHAR; VAR leds : SET): LONGINT;
VAR res: LONGINT;
BEGIN
CASE ch OF
028X: res := Inputs.KsReturn
|029X: res := Inputs.KsEscape
|02AX: res := Inputs.KsBackSpace
|02BX: res := Inputs.KsTab
|03AX: res := Inputs.KsF1
|03BX: res := Inputs.KsF2
|03CX: res := Inputs.KsF3
|03DX: res := Inputs.KsF4
|03EX: res := Inputs.KsF5
|03FX: res := Inputs.KsF6
|040X: res := Inputs.KsF7
|041X: res := Inputs.KsF8
|042X: res := Inputs.KsF9
|043X: res := Inputs.KsF10
|044X: res := Inputs.KsF11
|045X: res := Inputs.KsF12
|046X: res := Inputs.KsPrint
|047X: res := Inputs.KsScrollLock
|048X: res := Inputs.KsPause
|049X: res := Inputs.KsInsert
|04AX: res := Inputs.KsHome
|04BX: res := Inputs.KsPageUp
|04CX: res := Inputs.KsDelete
|04DX: res := Inputs.KsEnd
|04EX: res := Inputs.KsPageDown
|04FX: res := Inputs.KsRight
|050X: res := Inputs.KsLeft
|051X: res := Inputs.KsDown
|052X: res := Inputs.KsUp
|053X: res := Inputs.KsNumLock;
|054X: res := Inputs.KsKPDivide
|055X: res := Inputs.KsKPMultiply
|056X: res := Inputs.KsKPSubtract
|057X: res := Inputs.KsKPAdd
|058X: res := Inputs.KsReturn
|059X: IF ~(NumLock IN leds) THEN res := Inputs.KsEnd; ELSE res := Inputs.KsNil END;
|05AX: IF ~(NumLock IN leds) THEN res := Inputs.KsDown; ELSE res := Inputs.KsNil END;
|05BX: IF ~(NumLock IN leds) THEN res := Inputs.KsPageDown; ELSE res := Inputs.KsNil END;
|05CX: IF ~(NumLock IN leds) THEN res := Inputs.KsLeft; ELSE res := Inputs.KsNil END;
|05DX: IF ~(NumLock IN leds) THEN ch := 0X; res := Inputs.KsNil; ELSE res := Inputs.KsNil END;
|05EX: IF ~(NumLock IN leds) THEN res := Inputs.KsRight; ELSE res := Inputs.KsNil END;
|05FX: IF ~(NumLock IN leds) THEN res := Inputs.KsHome; ELSE res := Inputs.KsNil END;
|060X: IF ~(NumLock IN leds) THEN res := Inputs.KsUp; ELSE res := Inputs.KsNil END;
|061X: IF ~(NumLock IN leds) THEN res := Inputs.KsPageUp; ELSE res := Inputs.KsNil END;
|062X: IF ~(NumLock IN leds) THEN res := Inputs.KsInsert; ELSE res := Inputs.KsNil END;
|063X: IF ~(NumLock IN leds) THEN res := Inputs.KsDelete; ELSE res := Inputs.KsNil END;
|067X: IF ~(NumLock IN leds) THEN ch := 028X; res := Inputs.KsKPEnter; ELSE res := Inputs.KsNil END;
|0B0X: ch := 0X; res := Inputs.KsNil;
|0B1X: ch := 0X; res := Inputs.KsNil;
|09AX: res := Inputs.KsSysReq
|0E0X: res := Inputs.KsControlL
|0E1X: res := Inputs.KsShiftL
|0E2X: res := Inputs.KsAltL
|0E3X: res := Inputs.KsMetaL
|0E4X: res := Inputs.KsControlR
|0E5X: res := Inputs.KsShiftR
|0E6X: res := Inputs.KsAltR
|0E7X: res := Inputs.KsMetaR
|076X: res := Inputs.KsMenu
|0FFX: res := Inputs.KsBreak
ELSE
res := Inputs.KsNil
END;
RETURN res
END KeySym;
PROCEDURE GetModifierKeysym(modifier : LONGINT) : LONGINT;
VAR res : LONGINT;
BEGIN
CASE modifier OF
|Inputs.LeftCtrl: res := Inputs.KsControlL;
|Inputs.LeftShift: res := Inputs.KsShiftL;
|Inputs.LeftAlt: res := Inputs.KsAltL;
|Inputs.LeftMeta: res := Inputs.KsMetaL;
|Inputs.RightCtrl: res := Inputs.KsControlR;
|Inputs.RightShift: res := Inputs.KsShiftR;
|Inputs.RightAlt: res := Inputs.KsAltR;
|Inputs.RightMeta: res := Inputs.KsMetaR;
ELSE
res := Inputs.KsNil;
END;
RETURN res;
END GetModifierKeysym;
PROCEDURE Translate(flags, leds: SET; c: CHAR; keyboardTable : SYSTEM.ADDRESS; VAR keyboardDeadKey, keyboardKeyVal : LONGINT): LONGINT;
CONST
OScrollLock = 0;
ONumLock = 1;
OCapsLock = 2;
LAlt = 3;
RAlt = 4;
LCtrl = 5;
RCtrl = 6;
LShift = 7;
RShift = 8;
GreyEsc = 9;
LMeta = 13;
RMeta = 14;
Alt = {LAlt, RAlt};
Ctrl = {LCtrl, RCtrl};
Shift = {LShift, RShift};
DeadKey = 0;
VAR
a: SYSTEM.ADDRESS;
s1: CHAR;
s : SET;
k: INTEGER;
dkn: SHORTINT;
BEGIN
IF (c = 46X) & (flags * Inputs.Ctrl # {}) THEN RETURN -2 END;
IF (c = 44X) & (flags * Inputs.Ctrl # {}) THEN RETURN 0FFH END;
IF (c = 53X) & (flags * Inputs.Ctrl # {}) & (flags * Inputs.Alt # {}) THEN RETURN 0FFH END;
a := keyboardTable;
LOOP
SYSTEM.GET(a, s1);
IF s1 = 0FFX THEN
k := -1; keyboardDeadKey := 0; EXIT;
ELSIF s1 = c THEN
k := 0;
SYSTEM.GET(a+3, SYSTEM.VAL(CHAR, s));
dkn := SHORT(SHORT(SYSTEM.VAL(LONGINT, SYSTEM.LSH(s * {5..7}, -5))));
s := s * {DeadKey, ONumLock, OCapsLock, LAlt, RAlt, LCtrl, RCtrl};
IF ((s * Alt = SYSTEM.LSH(flags * Inputs.Alt,-2)) OR (ONumLock IN s) OR (s1>03BX)) & (dkn = keyboardDeadKey) THEN
IF flags * Inputs.Shift # {} THEN INCL(s, LShift) END;
IF (OCapsLock IN s) & (CapsLock IN leds) THEN s := s / {LShift} END;
IF ONumLock IN s THEN
IF flags * Inputs.Alt # {} THEN INCL(s, LShift)
ELSIF NumLock IN leds THEN s := s / {LShift}
END
END;
IF LShift IN s THEN SYSTEM.GET(a+2, SYSTEM.VAL(CHAR, k))
ELSE SYSTEM.GET(a+1, SYSTEM.VAL(CHAR, k))
END;
IF (DeadKey IN s) & (k <= 7) THEN
keyboardDeadKey := SHORT(k); k := -1
ELSIF k = 0FFH THEN
k := -1; keyboardDeadKey := 0
ELSE
IF flags * Inputs.Ctrl # {} THEN
IF ((k >= 64) & (k <= 95)) OR ((k >= 97) & (k <= 122)) THEN
k := SHORT(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, k) * {0..4}))
ELSIF k = 13 THEN
k := 10
END
END;
IF flags * Inputs.Alt # {} THEN
IF (k >= ORD("0")) & (k <= ORD("9")) & (NumLock IN s) THEN
IF keyboardKeyVal = -1 THEN keyboardKeyVal := k-ORD("0")
ELSE keyboardKeyVal := (10*keyboardKeyVal + (k-ORD("0"))) MOD 1000;
END;
k := -1
END
END;
keyboardDeadKey := 0
END;
EXIT
END
END;
INC(a, 4)
END;
RETURN k
END Translate;
PROCEDURE ShowFlags(flags, leds : SET);
BEGIN
KernelLog.String("Flags: ");
IF Inputs.LeftAlt IN flags THEN KernelLog.String("[Left Alt]"); END;
IF Inputs.RightAlt IN flags THEN KernelLog.String("[Right Alt]"); END;
IF Inputs.LeftCtrl IN flags THEN KernelLog.String("[Left Ctrl]"); END;
IF Inputs.RightCtrl IN flags THEN KernelLog.String("[Rigth Ctrl]"); END;
IF Inputs.LeftShift IN flags THEN KernelLog.String("[Left Shift]"); END;
IF Inputs.RightShift IN flags THEN KernelLog.String("[Right Shift]"); END;
IF Inputs.LeftMeta IN flags THEN KernelLog.String("[Left Meta]"); END;
IF Inputs.RightMeta IN flags THEN KernelLog.String("[Rigth Meta]"); END;
IF Inputs.Release IN flags THEN KernelLog.String("[Released]"); END;
IF ScrollLock IN leds THEN KernelLog.String("[ScrollLock]"); END;
IF NumLock IN leds THEN KernelLog.String("[NumLock]"); END;
IF CapsLock IN leds THEN KernelLog.String("[CapsLock]"); END;
IF Compose IN leds THEN KernelLog.String("[Compose]"); END;
IF Kana IN leds THEN KernelLog.String("[Kana]"); END;
END ShowFlags;
PROCEDURE Probe(dev : Usbdi.UsbDevice; if : Usbdi.InterfaceDescriptor) : Usbdi.Driver;
VAR driver : KeyboardDriver;
BEGIN
IF if.bInterfaceClass # 3 THEN RETURN NIL END;
IF if.bInterfaceSubClass # 1 THEN RETURN NIL END;
IF if.bInterfaceProtocol # 1 THEN RETURN NIL END;
IF if.bNumEndpoints # 1 THEN RETURN NIL END;
KernelLog.String("UsbKeyboard: USB Keyboard found."); KernelLog.Ln;
NEW(driver);
RETURN driver;
END Probe;
PROCEDURE SetLayout*(context : Commands.Context);
VAR
string : ARRAY 64 OF CHAR;
plugin : Plugins.Plugin; kd : KeyboardDriver;
BEGIN
context.arg.GetString(string);
IF (context.arg.res = Streams.Ok) & (string # "") THEN
plugin := Usb.usbDrivers.Get(string);
IF plugin # NIL THEN
IF plugin IS KeyboardDriver THEN
kd := plugin (KeyboardDriver);
ELSE context.error.String("UsbKeyboard: Device "); context.error.String(string); context.error.String(" is not a keyboard."); context.error.Ln;
END;
ELSE context.error.String("UsbKeyboard: Device "); context.error.String(string); context.error.String(" not found."); context.error.Ln;
END;
ELSE context.error.String("UsbKeyboard: Expected <dev> parameter."); context.error.Ln;
END;
IF kd # NIL THEN
context.arg.GetString(string);
IF (context.arg.res = Streams.Ok) & (string # "") THEN
kd.base.SetLayout(string);
context.out.String("Layout set to "); context.out.String(string); context.out.Ln;
END;
END;
END SetLayout;
PROCEDURE Install*;
END Install;
PROCEDURE Cleanup;
BEGIN
Usbdi.drivers.Remove(Name);
END Cleanup;
BEGIN
Modules.InstallTermHandler(Cleanup);
Usbdi.drivers.Add(Probe, Name, Description, Priority);
END UsbKeyboard.
UsbKeyboard.Install ~ SystemTools.Free UsbKeyboard ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyBE.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyCA.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyCH.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyD.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyDV.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyFR.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyIT.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyN.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyPL.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeySF.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyTR.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyUK.Bin ~
UsbKeyboard.SetLayout UsbKeyboard00 KeyUS.Bin ~
WMKeyCode.Open ~ SystemTools.Free WMKeyCode ~