This commit is contained in:
Devaev Maxim 2020-08-06 07:03:29 +03:00
parent 05984cee5d
commit 1196285045
14 changed files with 475 additions and 90 deletions

View File

@ -139,7 +139,8 @@ keymap: testenv
--volume `pwd`:/src \
-it $(TESTENV_IMAGE) bash -c "cd src \
&& ./genmap.py keymap.csv kvmd/keyboard/mappings.py.mako kvmd/keyboard/mappings.py \
&& ./genmap.py keymap.csv hid/src/keymap.h.mako hid/src/keymap.h \
&& ./genmap.py keymap.csv hid/src/usb/keymap.h.mako hid/src/usb/keymap.h \
&& ./genmap.py keymap.csv hid/src/ps2/keymap.h.mako hid/src/ps2/keymap.h \
"

View File

@ -61,7 +61,7 @@ class _X11Key:
class _KeyMapping:
web_name: str
serial_code: int
arduino_name: str
usb_name: str
otg_key: _OtgKey
ps2_key: _Ps2Key
at1_code: int
@ -99,15 +99,10 @@ def _parse_otg_key(key: str) -> _OtgKey:
def _parse_ps2_key(key: str) -> _Ps2Key:
(raw_type, raw_code) = key.split(":")
(code_type, raw_code) = key.split(":")
return _Ps2Key(
code=int(raw_code, 16),
type={
"reg": 0,
"spec": 1,
"pause": 2,
"print": 3,
}[raw_type],
type=code_type,
)
@ -119,7 +114,7 @@ def _read_keymap_csv(path: str) -> List[_KeyMapping]:
keymap.append(_KeyMapping(
web_name=row["web_name"],
serial_code=int(row["serial_code"]),
arduino_name=row["arduino_name"],
usb_name=row["usb_name"],
otg_key=_parse_otg_key(row["otg_key"]),
ps2_key=_parse_ps2_key(row["ps2_key"]),
at1_code=int(row["at1_code"], 16),

4
hid/.gitignore vendored
View File

@ -1,2 +1,2 @@
/.pioenvs/
/.piolibdeps/
/.pio/
/.current

View File

@ -1,16 +1,26 @@
all:
platformio run --environment $(if $(E),$(E),serial_prod)
usb:
make _build E=usb
ps2:
make _build E=ps2
_build:
rm -f .current
platformio run --environment $(E)
echo -n $(E) > .current
install: upload
upload:
platformio run --environment $(shell cat .current) --target upload
update:
platformio platform update
install: upload
upload:
platformio run --environment $(if $(E),$(E),serial_prod) --target upload
clean-all: clean
clean:
rm -rf .pio
rm -rf .pio .current
help:
@ cat Makefile

View File

@ -10,23 +10,33 @@
[common]
lib_deps =
HID-Project@2.6.1
TimerOne@1.1
build_flags =
-DCMD_SERIAL=Serial1
[env:serial_prod]
[env:usb]
platform = atmelavr
board = micro
framework = arduino
upload_port = /dev/ttyACM0
lib_deps = ${common.lib_deps}
build_flags = -DCMD_SERIAL=Serial1
lib_deps =
${common.lib_deps}
HID-Project@2.6.1
build_flags =
${common.build_flags}
-DHID_USB
extra_scripts = post:patch.py
[env:serial_test]
[env:ps2]
platform = atmelavr
board = micro
framework = arduino
upload_port = /dev/ttyACM0
lib_deps = ${common.lib_deps}
build_flags = -DCMD_SERIAL=Serial
extra_scripts = post:patch.py
lib_deps =
${common.lib_deps}
git+https://github.com/Harvie/ps2dev#v0.0.3
build_flags =
${common.build_flags}
-DHID_PS2
-DPS2_KBD_CLOCK_PIN=3
-DPS2_KBD_DATA_PIN=2

View File

@ -21,11 +21,16 @@
#include <Arduino.h>
#include <HID-Project.h>
#include <TimerOne.h>
#include "inline.h"
#include "keymap.h"
#if defined(HID_USB)
# include "usb/hid.h"
#elif defined(HID_PS2)
# include "ps2/hid.h"
#else
# error HID type is not selected
#endif
// #define CMD_SERIAL Serial1
@ -43,8 +48,8 @@
#define PROTO_RESP_PONG_PREFIX 0x80
#define PROTO_RESP_PONG_CAPS 0b00000001
#define PROTO_RESP_PONG_SCROLL 0x00000010
#define PROTO_RESP_PONG_NUM 0x00000100
#define PROTO_RESP_PONG_SCROLL 0b00000010
#define PROTO_RESP_PONG_NUM 0b00000100
#define PROTO_CMD_PING 0x01
#define PROTO_CMD_REPEAT 0x02
@ -62,48 +67,44 @@
#define PROTO_CMD_MOUSE_BUTTON_MIDDLE_STATE 0b00000010
// -----------------------------------------------------------------------------
#if defined(HID_USB)
UsbHid hid;
#elif defined(HID_PS2)
Ps2Hid hid;
#else
# error HID type is not selected
#endif
// -----------------------------------------------------------------------------
INLINE uint8_t cmdResetHid(const uint8_t *buffer) { // 0 bytes
BootKeyboard.releaseAll();
SingleAbsoluteMouse.releaseAll();
# ifdef HID_USB
hid.reset();
# endif
return PROTO_RESP_OK;
}
INLINE uint8_t cmdKeyEvent(const uint8_t *buffer) { // 2 bytes
KeyboardKeycode code = keymap(buffer[0]);
if (code != KEY_ERROR_UNDEFINED) {
if (buffer[1]) {
BootKeyboard.press(code);
} else {
BootKeyboard.release(code);
}
}
hid.sendKey(buffer[0], buffer[1]);
return PROTO_RESP_OK;
}
INLINE uint8_t cmdMouseButtonEvent(const uint8_t *buffer) { // 1 byte
# ifdef HID_USB
uint8_t state = buffer[0];
# define PROCESS_BUTTON(name) { \
if (state & PROTO_CMD_MOUSE_BUTTON_##name##_SELECT) { \
if (state & PROTO_CMD_MOUSE_BUTTON_##name##_STATE) { \
SingleAbsoluteMouse.press(MOUSE_##name); \
} else { \
SingleAbsoluteMouse.release(MOUSE_##name); \
} \
} \
}
PROCESS_BUTTON(LEFT);
PROCESS_BUTTON(RIGHT);
PROCESS_BUTTON(MIDDLE);
# undef PROCESS_BUTTON
hid.sendMouseButtons(
state & PROTO_CMD_MOUSE_BUTTON_LEFT_SELECT, state & PROTO_CMD_MOUSE_BUTTON_LEFT_STATE,
state & PROTO_CMD_MOUSE_BUTTON_RIGHT_SELECT, state & PROTO_CMD_MOUSE_BUTTON_RIGHT_STATE,
state & PROTO_CMD_MOUSE_BUTTON_MIDDLE_SELECT, state & PROTO_CMD_MOUSE_BUTTON_MIDDLE_STATE
);
# endif
return PROTO_RESP_OK;
}
INLINE uint8_t cmdMouseMoveEvent(const uint8_t *buffer) { // 4 bytes
# ifdef HID_USB
int x = (int)buffer[0] << 8;
x |= (int)buffer[1];
x = (x + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details
@ -112,34 +113,24 @@ INLINE uint8_t cmdMouseMoveEvent(const uint8_t *buffer) { // 4 bytes
y |= (int)buffer[3];
y = (y + 32768) / 2; // See /kvmd/apps/otg/hid/keyboard.py for details
SingleAbsoluteMouse.moveTo(x, y);
hid.sendMouseMove(x, y);
# endif
return PROTO_RESP_OK;
}
INLINE uint8_t cmdMouseWheelEvent(const uint8_t *buffer) { // 2 bytes
// delta_x is not supported by hid-project now
signed char delta_y = buffer[1];
SingleAbsoluteMouse.move(0, 0, delta_y);
# ifdef HID_USB
hid.sendMouseWheel(buffer[1]); // Y only, X is not supported
# endif
return PROTO_RESP_OK;
}
INLINE uint8_t cmdPongLeds(const uint8_t *buffer) { // 0 bytes
uint8_t leds = BootKeyboard.getLeds();
uint8_t response = PROTO_RESP_PONG_PREFIX;
# define PROCESS_LED(name) { \
if (leds & LED_##name##_LOCK) { \
response |= PROTO_RESP_PONG_##name; \
} \
}
PROCESS_LED(CAPS);
PROCESS_LED(SCROLL);
PROCESS_LED(NUM);
# undef PROCESS_LED
return response;
return ((uint8_t) PROTO_RESP_PONG_PREFIX) | hid.getLedsAs(
PROTO_RESP_PONG_CAPS,
PROTO_RESP_PONG_SCROLL,
PROTO_RESP_PONG_NUM
);
}
@ -199,8 +190,7 @@ void intRecvTimedOut() {
}
void setup() {
BootKeyboard.begin();
SingleAbsoluteMouse.begin();
hid.begin();
Timer1.attachInterrupt(intRecvTimedOut);
CMD_SERIAL.begin(CMD_SERIAL_SPEED);
@ -211,6 +201,10 @@ void loop() {
unsigned index = 0;
while (true) {
# ifdef HID_PS2
hid.periodic();
# endif
if (CMD_SERIAL.available() > 0) {
buffer[index] = (uint8_t)CMD_SERIAL.read();
if (index == 7) {

92
hid/src/ps2/hid.h Normal file
View File

@ -0,0 +1,92 @@
/*****************************************************************************
# #
# KVMD - The main Pi-KVM daemon. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#pragma once
#include <Arduino.h>
#include <ps2dev.h>
#include "../inline.h"
#include "keymap.h"
// #define PS2_KBD_CLOCK_PIN 3
// #define PS2_KBD_DATA_PIN 2
class Ps2Hid {
// https://wiki.osdev.org/PS/2_Keyboard
public:
Ps2Hid() : _dev(PS2_KBD_CLOCK_PIN, PS2_KBD_DATA_PIN) {}
void begin() {
_dev.keyboard_init();
}
INLINE void periodic() {
_dev.keyboard_handle(&_leds);
}
INLINE void sendKey(uint8_t code, bool state) {
Ps2KeyType ps2_type;
uint8_t ps2_code;
keymapPs2(code, &ps2_type, &ps2_code);
if (ps2_type != PS2_KEY_TYPE_UNKNOWN) {
// Не отправлялась часть нажатий. Когда clock на нуле, комп не принимает ничего от клавы.
// Этот костыль понижает процент пропущенных нажатий.
while (digitalRead(PS2_KBD_CLOCK_PIN) == 0) {};
if (state) {
switch (ps2_type) {
case PS2_KEY_TYPE_REG: _dev.keyboard_press(ps2_code); break;
case PS2_KEY_TYPE_SPEC: _dev.keyboard_press_special(ps2_code); break;
case PS2_KEY_TYPE_PRINT: _dev.keyboard_press_printscreen(); break;
case PS2_KEY_TYPE_PAUSE: _dev.keyboard_pausebreak(); break;
case PS2_KEY_TYPE_UNKNOWN: break;
}
} else {
switch (ps2_type) {
case PS2_KEY_TYPE_REG: _dev.keyboard_release(ps2_code); break;
case PS2_KEY_TYPE_SPEC: _dev.keyboard_release_special(ps2_code); break;
case PS2_KEY_TYPE_PRINT: _dev.keyboard_release_printscreen(); break;
case PS2_KEY_TYPE_PAUSE: break;
case PS2_KEY_TYPE_UNKNOWN: break;
}
}
}
}
INLINE uint8_t getLedsAs(uint8_t caps, uint8_t scroll, uint8_t num) {
uint8_t result = 0;
periodic();
if (_leds & 0b00000100) result |= caps;
if (_leds & 0b00000001) result |= scroll;
if (_leds & 0b00000010) result |= num;
return result;
}
private:
PS2dev _dev;
uint8_t _leds = 0;
};

148
hid/src/ps2/keymap.h Normal file
View File

@ -0,0 +1,148 @@
/*****************************************************************************
# #
# KVMD - The main Pi-KVM daemon. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#pragma once
#include "../inline.h"
enum Ps2KeyType : uint8_t {
PS2_KEY_TYPE_UNKNOWN = 0,
PS2_KEY_TYPE_REG = 1,
PS2_KEY_TYPE_SPEC = 2,
PS2_KEY_TYPE_PRINT = 3,
PS2_KEY_TYPE_PAUSE = 4,
};
INLINE void keymapPs2(uint8_t code, Ps2KeyType *ps2_type, uint8_t *ps2_code) {
*ps2_type = PS2_KEY_TYPE_UNKNOWN;
*ps2_code = 0;
switch (code) {
case 1: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 28; return; // KEY_A
case 2: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 50; return; // KEY_B
case 3: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 33; return; // KEY_C
case 4: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 35; return; // KEY_D
case 5: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 36; return; // KEY_E
case 6: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 43; return; // KEY_F
case 7: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 52; return; // KEY_G
case 8: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 51; return; // KEY_H
case 9: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 67; return; // KEY_I
case 10: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 59; return; // KEY_J
case 11: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 66; return; // KEY_K
case 12: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 75; return; // KEY_L
case 13: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 58; return; // KEY_M
case 14: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 49; return; // KEY_N
case 15: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 68; return; // KEY_O
case 16: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 77; return; // KEY_P
case 17: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 21; return; // KEY_Q
case 18: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 45; return; // KEY_R
case 19: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 27; return; // KEY_S
case 20: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 44; return; // KEY_T
case 21: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 60; return; // KEY_U
case 22: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 42; return; // KEY_V
case 23: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 29; return; // KEY_W
case 24: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 34; return; // KEY_X
case 25: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 53; return; // KEY_Y
case 26: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 26; return; // KEY_Z
case 27: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 22; return; // KEY_1
case 28: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 30; return; // KEY_2
case 29: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 38; return; // KEY_3
case 30: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 37; return; // KEY_4
case 31: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 46; return; // KEY_5
case 32: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 54; return; // KEY_6
case 33: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 61; return; // KEY_7
case 34: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 62; return; // KEY_8
case 35: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 70; return; // KEY_9
case 36: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 69; return; // KEY_0
case 37: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 90; return; // KEY_ENTER
case 38: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 118; return; // KEY_ESC
case 39: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 102; return; // KEY_BACKSPACE
case 40: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 13; return; // KEY_TAB
case 41: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 41; return; // KEY_SPACE
case 42: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 78; return; // KEY_MINUS
case 43: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 85; return; // KEY_EQUAL
case 44: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 84; return; // KEY_LEFT_BRACE
case 45: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 91; return; // KEY_RIGHT_BRACE
case 46: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 93; return; // KEY_BACKSLASH
case 47: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 76; return; // KEY_SEMICOLON
case 48: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 82; return; // KEY_QUOTE
case 49: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 14; return; // KEY_TILDE
case 50: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 65; return; // KEY_COMMA
case 51: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 73; return; // KEY_PERIOD
case 52: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 74; return; // KEY_SLASH
case 53: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 88; return; // KEY_CAPS_LOCK
case 54: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 5; return; // KEY_F1
case 55: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 6; return; // KEY_F2
case 56: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 4; return; // KEY_F3
case 57: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 12; return; // KEY_F4
case 58: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 3; return; // KEY_F5
case 59: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 11; return; // KEY_F6
case 60: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 131; return; // KEY_F7
case 61: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 10; return; // KEY_F8
case 62: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 1; return; // KEY_F9
case 63: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 9; return; // KEY_F10
case 64: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 120; return; // KEY_F11
case 65: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 7; return; // KEY_F12
case 66: *ps2_type = PS2_KEY_TYPE_PRINT; *ps2_code = 255; return; // KEY_PRINT
case 67: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 112; return; // KEY_INSERT
case 68: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 108; return; // KEY_HOME
case 69: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 125; return; // KEY_PAGE_UP
case 70: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 113; return; // KEY_DELETE
case 71: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 105; return; // KEY_END
case 72: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 122; return; // KEY_PAGE_DOWN
case 73: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 116; return; // KEY_RIGHT_ARROW
case 74: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 107; return; // KEY_LEFT_ARROW
case 75: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 114; return; // KEY_DOWN_ARROW
case 76: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 117; return; // KEY_UP_ARROW
case 77: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 20; return; // KEY_LEFT_CTRL
case 78: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 18; return; // KEY_LEFT_SHIFT
case 79: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 17; return; // KEY_LEFT_ALT
case 80: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 31; return; // KEY_LEFT_GUI
case 81: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 20; return; // KEY_RIGHT_CTRL
case 82: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 89; return; // KEY_RIGHT_SHIFT
case 83: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 17; return; // KEY_RIGHT_ALT
case 84: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 39; return; // KEY_RIGHT_GUI
case 85: *ps2_type = PS2_KEY_TYPE_PAUSE; *ps2_code = 255; return; // KEY_PAUSE
case 86: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 126; return; // KEY_SCROLL_LOCK
case 87: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 119; return; // KEY_NUM_LOCK
case 88: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 47; return; // KEY_MENU
case 89: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 74; return; // KEYPAD_DIVIDE
case 90: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 124; return; // KEYPAD_MULTIPLY
case 91: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 123; return; // KEYPAD_SUBTRACT
case 92: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 121; return; // KEYPAD_ADD
case 93: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 90; return; // KEYPAD_ENTER
case 94: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 105; return; // KEYPAD_1
case 95: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 114; return; // KEYPAD_2
case 96: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 122; return; // KEYPAD_3
case 97: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 107; return; // KEYPAD_4
case 98: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 115; return; // KEYPAD_5
case 99: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 116; return; // KEYPAD_6
case 100: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 108; return; // KEYPAD_7
case 101: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 117; return; // KEYPAD_8
case 102: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 125; return; // KEYPAD_9
case 103: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 112; return; // KEYPAD_0
case 104: *ps2_type = PS2_KEY_TYPE_REG; *ps2_code = 113; return; // KEYPAD_DOT
case 105: *ps2_type = PS2_KEY_TYPE_SPEC; *ps2_code = 94; return; // KEY_POWER
}
}

46
hid/src/ps2/keymap.h.mako Normal file
View File

@ -0,0 +1,46 @@
/*****************************************************************************
# #
# KVMD - The main Pi-KVM daemon. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#pragma once
#include "../inline.h"
enum Ps2KeyType : uint8_t {
PS2_KEY_TYPE_UNKNOWN = 0,
PS2_KEY_TYPE_REG = 1,
PS2_KEY_TYPE_SPEC = 2,
PS2_KEY_TYPE_PRINT = 3,
PS2_KEY_TYPE_PAUSE = 4,
};
<%! import operator %>
INLINE void keymapPs2(uint8_t code, Ps2KeyType *ps2_type, uint8_t *ps2_code) {
*ps2_type = PS2_KEY_TYPE_UNKNOWN;
*ps2_code = 0;
switch (code) {
% for km in sorted(keymap, key=operator.attrgetter("serial_code")):
case ${km.serial_code}: *ps2_type = PS2_KEY_TYPE_${km.ps2_key.type.upper()}; *ps2_code = ${km.ps2_key.code}; return; // ${km.usb_name}
% endfor
}
}

89
hid/src/usb/hid.h Normal file
View File

@ -0,0 +1,89 @@
/*****************************************************************************
# #
# KVMD - The main Pi-KVM daemon. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
*****************************************************************************/
#pragma once
#include <HID-Project.h>
#include "../inline.h"
#include "keymap.h"
// -----------------------------------------------------------------------------
class UsbHid {
public:
UsbHid() {}
void begin() {
BootKeyboard.begin();
SingleAbsoluteMouse.begin();
}
void reset() {
BootKeyboard.releaseAll();
SingleAbsoluteMouse.releaseAll();
}
INLINE void sendKey(uint8_t code, bool state) {
KeyboardKeycode usb_code = keymapUsb(code);
if (usb_code != KEY_ERROR_UNDEFINED) {
if (state) BootKeyboard.press(usb_code);
else BootKeyboard.release(usb_code);
}
}
INLINE void sendMouseButtons(
bool left_select, bool left_state,
bool right_select, bool right_state,
bool middle_select, bool middle_state
) {
if (left_select) sendMouseButton(MOUSE_LEFT, left_state);
if (right_select) sendMouseButton(MOUSE_RIGHT, right_state);
if (middle_select) sendMouseButton(MOUSE_MIDDLE, middle_state);
}
INLINE void sendMouseMove(int x, int y) {
SingleAbsoluteMouse.moveTo(x, y);
}
INLINE void sendMouseWheel(int delta_y) {
// delta_x is not supported by hid-project now
SingleAbsoluteMouse.move(0, 0, delta_y);
}
INLINE uint8_t getLedsAs(uint8_t caps, uint8_t scroll, uint8_t num) {
uint8_t leds = BootKeyboard.getLeds();
uint8_t result = 0;
if (leds & LED_CAPS_LOCK) result |= caps;
if (leds & LED_SCROLL_LOCK) result |= scroll;
if (leds & LED_NUM_LOCK) result |= num;
return result;
}
private:
INLINE void sendMouseButton(uint8_t button, bool state) {
if (state) SingleAbsoluteMouse.press(button);
else SingleAbsoluteMouse.release(button);
}
};

View File

@ -24,11 +24,11 @@
#include <HID-Project.h>
#include "inline.h"
#include "../inline.h"
INLINE KeyboardKeycode keymap(uint8_t code) {
switch(code) {
INLINE KeyboardKeycode keymapUsb(uint8_t code) {
switch (code) {
case 1: return KEY_A;
case 2: return KEY_B;
case 3: return KEY_C;

View File

@ -24,13 +24,13 @@
#include <HID-Project.h>
#include "inline.h"
#include "../inline.h"
<%! import operator %>
INLINE KeyboardKeycode keymap(uint8_t code) {
switch(code) {
INLINE KeyboardKeycode keymapUsb(uint8_t code) {
switch (code) {
% for km in sorted(keymap, key=operator.attrgetter("serial_code")):
case ${km.serial_code}: return ${km.arduino_name};
case ${km.serial_code}: return ${km.usb_name};
% endfor
default: return KEY_ERROR_UNDEFINED;
}

View File

@ -1,4 +1,4 @@
web_name,serial_code,arduino_name,otg_key,ps2_key,at1_code,x11_names
web_name,serial_code,usb_name,otg_key,ps2_key,at1_code,x11_names
KeyA,1,KEY_A,0x04,reg:0x1c,0x1e,"^XK_A,XK_a"
KeyB,2,KEY_B,0x05,reg:0x32,0x30,"^XK_B,XK_b"
KeyC,3,KEY_C,0x06,reg:0x21,0x2e,"^XK_C,XK_c"

1 web_name serial_code arduino_name usb_name otg_key ps2_key at1_code x11_names
2 KeyA 1 KEY_A 0x04 reg:0x1c 0x1e ^XK_A,XK_a
3 KeyB 2 KEY_B 0x05 reg:0x32 0x30 ^XK_B,XK_b
4 KeyC 3 KEY_C 0x06 reg:0x21 0x2e ^XK_C,XK_c

View File

@ -24,11 +24,11 @@ fake_rpi.RPi.GPIO
_KeyMapping.web_name
_KeyMapping.serial_code
_KeyMapping.arduino_name
_KeyMapping.otg_code
_KeyMapping.otg_is_modifier
_KeyMapping.usb_name
_KeyMapping.otg_key
_KeyMapping.ps2_key
_KeyMapping.at1_code
_KeyMapping.x11_codes
_KeyMapping.x11_keys
_SharedParams.width
_SharedParams.height