39 Commits

Author SHA1 Message Date
844f76e2c2 HID: Mouse raw send to HID device 2020-06-07 15:09:19 +02:00
43b82fd669 HID: Mouse disable json send 2020-06-07 15:08:35 +02:00
0dbf3f9b7a HID: mouse RAW data 2020-06-07 15:07:12 +02:00
42ec2611e3 HID: mouse RAW data 2020-06-07 14:54:55 +02:00
beaad49558 HID: change POST to socketio 2020-06-07 14:29:55 +02:00
44d01c0127 HID: fix zapis 2020-06-07 14:28:27 +02:00
cf5ee01a9c HID: fix ret 2020-06-07 14:27:28 +02:00
0416f32744 HID: removed keystroke for kvm 2020-06-07 14:25:04 +02:00
009d008b5b HID: change POST to socketio 2020-06-07 14:24:15 +02:00
19086199c0 HID Input: KVM page (merge image with hid) 2020-06-07 13:38:06 +02:00
50ab6c43fc HID Input: listen on IPv6 2020-06-07 13:37:45 +02:00
33bc12cb8a Gadget: mass storage name 2020-06-07 13:37:30 +02:00
2a22d0b2bf Docs 2020-06-05 18:15:26 +02:00
ad8a962be8 Gadget: keyboard descriptor to variable 2020-06-05 18:12:44 +02:00
6aaa2f5b0d Gadget: FIX mouse HID for windows 2020-06-05 17:57:19 +02:00
11119bb1cb HID Templates: first merge kbd and mouse 2020-06-05 17:28:34 +02:00
1fa5e4be16 HID Input: cleanup 2020-06-05 17:17:58 +02:00
30e6b30893 HID Input: removed relative mouse, removed POST mouse 2020-06-05 17:17:17 +02:00
dcea5e5dca Gadget: removed relative mouse 2020-06-05 17:16:52 +02:00
bbbf8cbbf6 HID mouse: wheel 2020-06-05 17:06:08 +02:00
6c1bd1235d Mouse template 2020-06-05 17:05:48 +02:00
478cb9c202 HID: run HID service 2020-06-05 16:43:14 +02:00
deb2139d96 HID: mouse over socketio 2020-06-05 16:42:23 +02:00
12644f1e39 HID Input: socketIO mouse 2020-06-05 16:37:44 +02:00
fb2c4b4874 HID Input: socketIO test 2020-06-05 16:32:24 +02:00
ce4842d93e SocketIO: test 2020-06-05 16:14:56 +02:00
3563b19073 Gadget: HID permissions 2020-06-05 15:15:27 +02:00
06519e7009 HID Mouse: absolute mouse support 2020-06-05 15:04:27 +02:00
f22f2eeb67 Gadget: MOUSE1 resolution 1920x1080 2020-06-05 14:01:43 +02:00
d077d034aa Gadget: MOUSE0 descriptor to variable 2020-06-05 13:20:12 +02:00
7d37ff9696 Gadget: MOUSE1 descriptor to variable, separated wheel 2020-06-05 13:04:15 +02:00
fe08a9574d Gadget: absolute mouse position test 2020-06-04 16:21:24 +02:00
ff1af4831f hid descriptors 2020-06-04 16:20:39 +02:00
76ff93ad58 Gadget: config name 2020-06-04 14:06:16 +02:00
78463d1ac9 Gadget: added secondary mouse, prepare for absolute 2020-06-04 14:00:54 +02:00
5853ae6dda Code style 2020-06-04 13:50:01 +02:00
4cfea640f9 JS Keymap: use reversed key/value map 2020-06-04 13:43:51 +02:00
ef225cbbb4 JS keymap: because of firefox send different eventname 2020-05-25 10:15:16 +02:00
bd776abe91 Kbd Hid: FIX MOD meta act as 'e' char 2020-05-25 10:14:49 +02:00
13 changed files with 685 additions and 426 deletions

View File

@@ -5,6 +5,38 @@ gserial=$(awk '/Serial/ { print $3 }' /proc/cpuinfo)
gmanufacturer="Petrkr.NET" gmanufacturer="Petrkr.NET"
gproduct="rPi KVM" gproduct="rPi KVM"
KEYBOARD=""
KEYBOARD="$KEYBOARD\\x05\\x01\\x09\\x06" # Usage generic desktop, Usage keyboard
KEYBOARD="$KEYBOARD\\xa1\\x01\\x05\\x07" # Collection App, Use page Keyboard
KEYBOARD="$KEYBOARD\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08" # Usage min (LeftControl) max (Right GUI), log min 0 log min 1, report size 1 count 8
KEYBOARD="$KEYBOARD\\x81\\x02" # Input data, variable, absolute
KEYBOARD="$KEYBOARD\\x75\\x08\\x95\\x01" # Report size 8, count 1
KEYBOARD="$KEYBOARD\\x81\\x03" # Input Const, variable, absolute
KEYBOARD="$KEYBOARD\\x75\\x01\\x95\\x05" # Report size 1 count 5
KEYBOARD="$KEYBOARD\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\xff\\x05\\x07\\x19\\x00\\x29\\x65"
KEYBOARD="$KEYBOARD\\x81\\x00" # Input data array absolute
KEYBOARD="$KEYBOARD\\xc0" # End Collection Application
#Mouse absolute descriptor
MOUSE0=""
MOUSE0="$MOUSE0\\x05\\x01\\x09\\x02" # Usage generic desktop, Usage mouse
MOUSE0="$MOUSE0\\xa1\\x01\\x09\\x01" # Collection App, Usage Pointer
MOUSE0="$MOUSE0\\xa1\\x00" # Collection Physical
MOUSE0="$MOUSE0\\x05\\x09" # Use Page buttons
MOUSE0="$MOUSE0\\x19\\x01\\x29\\x08\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08" # Usage min 1, max 8, logical min 0, max 1, report 8, size 1
MOUSE0="$MOUSE0\\x81\\x02" # Input data, variable, absolute
MOUSE0="$MOUSE0\\x05\\x01" # Usage page generic desktop
MOUSE0="$MOUSE0\\x09\\x30\\x35\\x00\\x46\\x80\\x07\\x15\\x00\\x26\\x80\\x07\\x75\\x10\\x95\\x01" # Usage X, Log min 0, log max 1920, size 16, report 1
MOUSE0="$MOUSE0\\x81\\x02" # Input data, variable, absolute
MOUSE0="$MOUSE0\\x05\\x01" # Usage page generic desktop
MOUSE0="$MOUSE0\\x09\\x31\\x35\\x00\\x46\\x38\\x04\\x15\\x00\\x26\\x38\\x04\\x75\\x10\\x95\\x01" # Usage Y, Log min 0, log max 1080, size 16, report 1
MOUSE0="$MOUSE0\\x81\\x02" # Input data, variable, absolute
MOUSE0="$MOUSE0\\x05\\x01" # Usage page generic desktop
MOUSE0="$MOUSE0\\x09\\x38\\x35\\x00\\x45\\x00\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x01" # Usage Wheel, log min -127, max 127, size 8, report 1
MOUSE0="$MOUSE0\\x81\\x06" # Input data, variable, relative
MOUSE0="$MOUSE0\\xc0" # End collection Physical
MOUSE0="$MOUSE0\\xc0" # End collection Application
cd /sys/kernel/config/usb_gadget/ cd /sys/kernel/config/usb_gadget/
mkdir -p $gname mkdir -p $gname
cd $gname cd $gname
@@ -22,7 +54,7 @@ echo "$gmanufacturer" > strings/0x409/manufacturer
echo "$gproduct" > strings/0x409/product echo "$gproduct" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409 mkdir -p configs/c.1/strings/0x409
echo "Config: HID KBD" > configs/c.1/strings/0x409/configuration echo "Config: KVM Composite" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower echo 250 > configs/c.1/MaxPower
echo "Creating usb devices" echo "Creating usb devices"
@@ -32,23 +64,25 @@ mkdir -p functions/hid.kbd0
echo 1 > functions/hid.kbd0/protocol echo 1 > functions/hid.kbd0/protocol
echo 1 > functions/hid.kbd0/subclass echo 1 > functions/hid.kbd0/subclass
echo 8 > functions/hid.kbd0/report_length echo 8 > functions/hid.kbd0/report_length
echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\xff\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.kbd0/report_desc echo -ne $KEYBOARD > functions/hid.kbd0/report_desc
echo " HID Mouse" echo " HID Mouse"
mkdir -p functions/hid.mouse0 mkdir -p functions/hid.mouse0
echo 2 > functions/hid.mouse0/protocol echo 2 > functions/hid.mouse0/protocol
echo 1 > functions/hid.mouse0/subclass echo 1 > functions/hid.mouse0/subclass
echo 8 > functions/hid.mouse0/report_length echo 8 > functions/hid.mouse0/report_length
echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x08\\x15\\x00\\x25\\x01\\x95\\x08\\x75\\x01\\x81\\x02\\x05\\x01\\x09\\x30\\x09\\x31\\x09\\x38\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x03\\x81\\x06\\xc0\\xc0 > functions/hid.mouse0/report_desc echo -ne $MOUSE0 > functions/hid.mouse0/report_desc
echo " Mass storage" echo " Mass storage"
mkdir -p functions/mass_storage.disk1 mkdir -p functions/mass_storage.disk1
echo "RPi KVM DISK" > functions/mass_storage.disk1/lun.0/inquiry_string
echo " CD-ROM" echo " CD-ROM"
mkdir -p functions/mass_storage.cdrom1 mkdir -p functions/mass_storage.cdrom1
echo 1 > functions/mass_storage.cdrom1/lun.0/cdrom echo 1 > functions/mass_storage.cdrom1/lun.0/cdrom
echo 1 > functions/mass_storage.cdrom1/lun.0/removable echo 1 > functions/mass_storage.cdrom1/lun.0/removable
echo "RPi KVM CDROM" > functions/mass_storage.cdrom1/lun.0/inquiry_string
echo "Activating gadgeds" echo "Activating gadgeds"
@@ -60,3 +94,7 @@ ln -s functions/mass_storage.cdrom1 configs/c.1/
echo "Turn on gadget" echo "Turn on gadget"
ls /sys/class/udc > UDC ls /sys/class/udc > UDC
echo "Change permissions"
chgrp input /dev/hidg0; chmod 660 /dev/hidg0
chgrp input /dev/hidg1; chmod 660 /dev/hidg1

60
hid_descriptors.txt Normal file
View File

@@ -0,0 +1,60 @@
https://github.com/arduino/Arduino/blob/da9641410a4b8fa0865f0a31d0b884d14f5e7670/hardware/arduino/avr/cores/arduino/HID.cpp
05 01 // Usage page Generic desktop
09 02 // Usage Mouse
a1 01 // Collection Application
09 01 // Usage Pointer
a1 00 // Collection Physical
05 09 // Usage Page Buttons
19 01 // Usage Min 01
29 08 // Usage Max 08
15 00 // Logical min 0
25 01 // Logical max 1
95 08 // Report count 8
75 01 // Report size 1
81 02 // Input Data, Variable, Absolute
05 01 // Usage Page Generic Desktop
09 30 // Usage X
09 31 // Usage Y
15 00 // Logical Min ( 0)
25 FF // Logical Max ( 255)
75 08 // Report size 8
95 02 // Report count 2
81 02 // Input Data, Variable, Absolute
05 01 // Usage Page Generic Desktop
09 38 // Usage Wheel
15 81 // Logical Min (-127)
25 7f // Logical Max ( 127)
75 08 // Report size 8
95 01 // Report count 1
81 06 // Input Data, Variable, Relative
c0 // End collection
c0 // End collection
00010101
00100101
input bytes (4 bytes)
0 - 0 data / 1 constant
1 - 0 array / 1 variable
2 - 0 absolute / 1 relative
3 - 0 no wrap / 1 wrap
4 - 0 linear / 1 non linear
5 - 0 prefered state / 1 no preferred
6 - 0 no null pos / 1 null state
7 - 0 non volatile / 1 volatile
8 - 0 bit field / 1 buffered bytes
9 - 31 reserved
00000110
|||
||\ --> data
|\--> variable
\--> relative

View File

@@ -2,28 +2,28 @@ from flask import Response
from flask import Flask from flask import Flask
from flask import render_template from flask import render_template
from flask import request from flask import request
import threading from flask_socketio import SocketIO
import argparse import argparse
import datetime
import time
import json import json
import struct
from hidkeycodes import hidkeycodes from hidkeycodes import hidkeycodes
from jskeycodes import jskeycodes from jskeycodes import jscodehidmap
lock = threading.Lock()
# initialize a flask object # initialize a flask object
app = Flask(__name__) app = Flask(__name__)
socketio = SocketIO(app)
hiddev = None hiddev = None
hidmouse = None hidmouseabs = None
def hid_init(): def hid_init():
global hiddev, hidmouse global hiddev, hidmouseabs
hiddev=open('/dev/hidg0', 'rb+') hiddev = open('/dev/hidg0', 'rb+')
hidmouse=open('/dev/hidg1', 'rb+') hidmouseabs = open('/dev/hidg1', 'rb+')
def hid_write(data): def hid_write(data):
if hiddev is None: if hiddev is None:
@@ -32,21 +32,22 @@ def hid_write(data):
hiddev.write(data) hiddev.write(data)
hiddev.flush() hiddev.flush()
def hid_mouse_write(btn, x, y, wheel):
if hidmouse is None: def hid_mouse_writeabs(btn, x, y, wheel):
if hidmouseabs is None:
return False return False
data = bytearray(4) data = bytearray(6)
data[0] = btn data[0] = btn
data[1] = x data[1:3] = x.to_bytes(2, byteorder='little')
data[2] = y data[3:5] = y.to_bytes(2, byteorder='little')
data[3] = wheel data[5] = wheel
hidmouse.write(data) hidmouseabs.write(data)
hidmouse.flush() hidmouseabs.flush()
def send_key(hidkey, shift, alt, ctlr): def send_key(hidkey, shift, alt, ctlr, mod):
data = bytearray(8) data = bytearray(8)
if shift: if shift:
data[0] += hidkeycodes['KEY_MOD_LSHIFT'] data[0] += hidkeycodes['KEY_MOD_LSHIFT']
@@ -55,9 +56,9 @@ def send_key(hidkey, shift, alt, ctlr):
if ctlr: if ctlr:
data[0] += hidkeycodes['KEY_MOD_LCTRL'] data[0] += hidkeycodes['KEY_MOD_LCTRL']
if hidkey == hidkeycodes['KEY_MOD_LMETA'] or hidkey == hidkeycodes['KEY_MOD_RMETA']: if mod and (hidkey == hidkeycodes['KEY_MOD_LMETA'] or hidkey == hidkeycodes['KEY_MOD_RMETA']):
data[0] += hidkey data[0] += hidkey
hidkey=0 hidkey = 0
data[2] = hidkey data[2] = hidkey
@@ -69,8 +70,8 @@ def get_hid_by_jscode(rawkeycode):
hidkeycode = None hidkeycode = None
hidkeyname = None hidkeyname = None
if rawkeycode in jskeycodes.values(): if rawkeycode in jscodehidmap:
hidkeyname = list(jskeycodes.keys())[list(jskeycodes.values()).index(rawkeycode)] hidkeyname = jscodehidmap[rawkeycode]
if hidkeyname in hidkeycodes: if hidkeyname in hidkeycodes:
hidkeycode = hidkeycodes[hidkeyname] hidkeycode = hidkeycodes[hidkeyname]
else: else:
@@ -80,44 +81,62 @@ def get_hid_by_jscode(rawkeycode):
print ("JS key: {} HID key: {}({})".format(rawkeycode, hidkeyname, hidkeycode)) print ("JS key: {} HID key: {}({})".format(rawkeycode, hidkeyname, hidkeycode))
return hidkeycode return hidkeycode, (hidkeyname is not None and "MOD" in hidkeyname)
@app.route("/") @app.route("/")
def index(): def index():
return render_template("hid.html") return render_template("hid.html")
@app.route("/kvm.html")
def kvm():
return render_template("kvm.html")
@app.route("/mouse.html") @app.route("/mouse.html")
def mouseindex(): def mouseindex():
return render_template("mouse.html") return render_template("mouse.html")
@app.route("/keyboard.html")
def keyboardIndex():
return render_template("keyboard.html")
@app.route("/hid/mouse", methods=["POST"]) @socketio.on('mouseEventRaw')
def mouse(): def handle_mouseEvent(data):
mouseevent = json.loads(request.data) print(data)
btn = data[0]
x = data[1]
y = data[2]
wheel = data[3]
print("RAW Btn: {}, X: {}, Y: {}, W: {}".format(btn, x, y, wheel))
hid_mouse_writeabs(btn, x, y, wheel)
@socketio.on('mouseEvent')
def handle_mouseEvent(data):
mouseevent = json.loads(data)
print(mouseevent) print(mouseevent)
btn = mouseevent['btn'] btn = mouseevent['btn']
x = mouseevent['x'] x = mouseevent['x']
y = mouseevent['y'] y = mouseevent['y']
wheel = mouseevent['wheel'] wheel = mouseevent['wheel']
wheel = wheel if wheel >= 0 else 255-abs(wheel)
x = x if x >= 0 else 255-abs(x) print("X: {}, Y: {}".format(x, y))
y = y if y >= 0 else 255-abs(y)
print ("X: {}, Y: {}".format(x,y)) hid_mouse_writeabs(btn, x, y, wheel)
hid_mouse_write(btn, x, y, wheel)
return Response("", mimetype = "text/plain")
@app.route("/hid/keyboard", methods=["POST"]) @socketio.on('kbdEvent')
def keypress(): def handle_kbdEvent(data):
keyevent = json.loads(request.data) keyevent = json.loads(data)
print ("Raw data: {}".format(request.data)) print("Raw data: {}".format(data))
rawkeycode = keyevent['code'] rawkeycode = keyevent['code']
hidkeycode = get_hid_by_jscode(rawkeycode) hidkeycode, mod = get_hid_by_jscode(rawkeycode)
if hidkeycode is not None: if hidkeycode is not None:
try: try:
@@ -125,12 +144,13 @@ def keypress():
hidkeycode, hidkeycode,
keyevent['shiftKey'], keyevent['shiftKey'],
keyevent['altKey'], keyevent['altKey'],
keyevent['ctrlKey']) keyevent['ctrlKey'],
mod)
except Exception as e: except Exception as e:
print("Error sending HID message", e) print("Error sending HID message", e)
return Response("Press {}".format(hidkeycode), mimetype = "text/plain")
hid_init()
# check to see if this is the main thread of execution # check to see if this is the main thread of execution
if __name__ == '__main__': if __name__ == '__main__':
@@ -144,14 +164,5 @@ if __name__ == '__main__':
help="# of frames used to construct the background model") help="# of frames used to construct the background model")
args = vars(ap.parse_args()) args = vars(ap.parse_args())
hid_init()
app.run(host=args["ip"], port=args["port"], debug=True, app.run(host=args["ip"], port=args["port"], debug=True,
threaded=True, use_reloader=False) use_reloader=False)
# Clean up
if hiddev is not None:
print("Closing hid")
hiddev.close()

View File

@@ -1,245 +1,129 @@
jscodehidmap = {
'KeyA': 'KEY_A',
'KeyB': 'KEY_B',
'KeyC': 'KEY_C',
'KeyD': 'KEY_D',
'KeyE': 'KEY_E',
'KeyF': 'KEY_F',
'KeyG': 'KEY_G',
'KeyH': 'KEY_H',
'KeyI': 'KEY_I',
'KeyJ': 'KEY_J',
'KeyK': 'KEY_K',
'KeyL': 'KEY_L',
'KeyM': 'KEY_M',
'KeyN': 'KEY_N',
'KeyO': 'KEY_O',
'KeyP': 'KEY_P',
'KeyQ': 'KEY_Q',
'KeyR': 'KEY_R',
'KeyS': 'KEY_S',
'KeyT': 'KEY_T',
'KeyU': 'KEY_U',
'KeyV': 'KEY_V',
'KeyW': 'KEY_W',
'KeyX': 'KEY_X',
'KeyY': 'KEY_Y',
'KeyZ': 'KEY_Z',
jskeycodes = { 'Backquote': 'KEY_GRAVE',
'KEY_A': 'KeyA',
'KEY_B': 'KeyB',
'KEY_C': 'KeyC',
'KEY_D': 'KeyD',
'KEY_E': 'KeyE',
'KEY_F': 'KeyF',
'KEY_G': 'KeyG',
'KEY_H': 'KeyH',
'KEY_I': 'KeyI',
'KEY_J': 'KeyJ',
'KEY_K': 'KeyK',
'KEY_L': 'KeyL',
'KEY_M': 'KeyM',
'KEY_N': 'KeyN',
'KEY_O': 'KeyO',
'KEY_P': 'KeyP',
'KEY_Q': 'KeyQ',
'KEY_R': 'KeyR',
'KEY_S': 'KeyS',
'KEY_T': 'KeyT',
'KEY_U': 'KeyU',
'KEY_V': 'KeyV',
'KEY_W': 'KeyW',
'KEY_X': 'KeyX',
'KEY_Y': 'KeyY',
'KEY_Z': 'KeyZ',
'KEY_GRAVE': 'Backquote', 'Digit0': 'KEY_0',
'Digit1': 'KEY_1',
'Digit2': 'KEY_2',
'Digit3': 'KEY_3',
'Digit4': 'KEY_4',
'Digit5': 'KEY_5',
'Digit6': 'KEY_6',
'Digit7': 'KEY_7',
'Digit8': 'KEY_8',
'Digit9': 'KEY_9',
'KEY_0': 'Digit0', 'Minus': 'KEY_MINUS',
'KEY_1': 'Digit1', 'Equal': 'KEY_EQUAL',
'KEY_2': 'Digit2',
'KEY_3': 'Digit3',
'KEY_4': 'Digit4',
'KEY_5': 'Digit5',
'KEY_6': 'Digit6',
'KEY_7': 'Digit7',
'KEY_8': 'Digit8',
'KEY_9': 'Digit9',
'KEY_MINUS': 'Minus', 'BracketLeft': 'KEY_LEFTBRACE',
'KEY_EQUAL': 'Equal', 'BracketRight': 'KEY_RIGHTBRACE',
'KEY_LEFTBRACE': 'BracketLeft', 'Semicolon': 'KEY_SEMICOLON',
'KEY_RIGHTBRACE': 'BracketRight', 'Quote': 'KEY_APOSTROPHE',
'Backslash': 'KEY_BACKSLASH',
'KEY_SEMICOLON': 'Semicolon', 'Comma': 'KEY_COMMA',
'KEY_APOSTROPHE': 'Quote', 'Period': 'KEY_DOT',
'KEY_BACKSLASH': 'Backslash', 'Slash': 'KEY_SLASH',
'KEY_COMMA': 'Comma', 'IntlBackslash': 'KEY_102ND',
'KEY_DOT': 'Period',
'KEY_SLASH': 'Slash',
'KEY_102ND': 'IntlBackslash', 'Numpad0': 'KEY_KP0',
'Numpad1': 'KEY_KP1',
'Numpad2': 'KEY_KP2',
'Numpad3': 'KEY_KP3',
'Numpad4': 'KEY_KP4',
'Numpad5': 'KEY_KP5',
'Numpad6': 'KEY_KP6',
'Numpad7': 'KEY_KP7',
'Numpad8': 'KEY_KP8',
'Numpad9': 'KEY_KP9',
'KEY_KP0': 'Numpad0', 'NumpadMultiply': 'KEY_KPASTERISK',
'KEY_KP1': 'Numpad1', 'NumpadAdd': 'KEY_KPPLUS',
'KEY_KP2': 'Numpad2', 'NumpadSubtract': 'KEY_KPMINUS',
'KEY_KP3': 'Numpad3', 'NumpadDecimal': 'KEY_KPDOT',
'KEY_KP4': 'Numpad4', 'NumpadDivide': 'KEY_KPSLASH',
'KEY_KP5': 'Numpad5', 'NumpadEnter': 'KEY_KPENTER',
'KEY_KP6': 'Numpad6',
'KEY_KP7': 'Numpad7',
'KEY_KP8': 'Numpad8',
'KEY_KP9': 'Numpad9',
'KEY_KPASTERISK': 'NumpadMultiply',
'KEY_KPPLUS': 'NumpadAdd',
'KEY_KPMINUS': 'NumpadSubtract',
'KEY_KPDOT': 'NumpadDecimal',
'KEY_KPSLASH': 'NumpadDivide',
'KEY_KPENTER': 'NumpadEnter',
'KEY_ESC': 'Escape', 'Escape': 'KEY_ESC',
'KEY_F1': 'F1', 'F1': 'KEY_F1',
'KEY_F2': 'F2', 'F2': 'KEY_F2',
'KEY_F3': 'F3', 'F3': 'KEY_F3',
'KEY_F4': 'F4', 'F4': 'KEY_F4',
'KEY_F5': 'F5', 'F5': 'KEY_F5',
'KEY_F6': 'F6', 'F6': 'KEY_F6',
'KEY_F7': 'F7', 'F7': 'KEY_F7',
'KEY_F8': 'F8', 'F8': 'KEY_F8',
'KEY_F9': 'F9', 'F9': 'KEY_F9',
'KEY_F10': 'F10', 'F10': 'KEY_F10',
'KEY_F11': 'F11', 'F11': 'KEY_F11',
'KEY_F12': 'F12', 'F12': 'KEY_F12',
'KEY_F13': 'F13', 'F13': 'KEY_F13',
'KEY_F14': 'F14', 'F14': 'KEY_F14',
'KEY_F15': 'F15', 'F15': 'KEY_F15',
'KEY_F16': 'F16', 'F16': 'KEY_F16',
'KEY_F17': 'F17', 'F17': 'KEY_F17',
'KEY_F18': 'F18', 'F18': 'KEY_F18',
'KEY_F19': 'F19', 'F19': 'KEY_F19',
'KEY_F20': 'F20', 'F20': 'KEY_F20',
'KEY_F21': 'F21', 'F21': 'KEY_F21',
'KEY_F22': 'F22', 'F22': 'KEY_F22',
'KEY_F23': 'F23', 'F23': 'KEY_F23',
'KEY_BACKSPACE': 'Backspace', 'Backspace': 'KEY_BACKSPACE',
'KEY_SPACE': 'Space', 'Space': 'KEY_SPACE',
'KEY_TAB': 'Tab', 'Tab': 'KEY_TAB',
'KEY_ENTER' : 'Enter', 'Enter': 'KEY_ENTER',
'KEY_PAGEUP': 'PageUp', 'PageUp': 'KEY_PAGEUP',
'KEY_PAGEDOWN': 'PageDown', 'PageDown': 'KEY_PAGEDOWN',
'KEY_HOME': 'Home', 'Home': 'KEY_HOME',
'KEY_END': 'End', 'End': 'KEY_END',
'KEY_INSERT': 'Insert', 'Insert': 'KEY_INSERT',
'KEY_DELETE': 'Delete', 'Delete': 'KEY_DELETE',
'KEY_UP': 'ArrowUp', 'ArrowUp': 'KEY_UP',
'KEY_DOWN': 'ArrowDown', 'ArrowDown': 'KEY_DOWN',
'KEY_LEFT': 'ArrowLeft', 'ArrowLeft': 'KEY_LEFT',
'KEY_RIGHT': 'ArrowRight', 'ArrowRight': 'KEY_RIGHT',
'KEY_NUMLOCK': 'NumLock', 'NumLock': 'KEY_NUMLOCK',
'KEY_CAPSLOCK': 'CapsLock', 'CapsLock': 'KEY_CAPSLOCK',
'KEY_SCROLLLOCK': 'ScrollLock', 'ScrollLock': 'KEY_SCROLLLOCK',
'KEY_MOD_LMETA': 'MetaLeft', 'MetaLeft': 'KEY_MOD_LMETA',
'KEY_MOD_RMETA': 'MetaRight', 'MetaRight': 'KEY_MOD_RMETA',
'KEY_COMPOSE': 'ContextMenu', 'OSLeft': 'KEY_MOD_LMETA',
} 'OSRight': 'KEY_MOD_RMETA',
jskeywhich = { 'ContextMenu': 'KEY_COMPOSE'
'KEY_CANCEL': 3,
'KEY_BACKSPACE': 8,
'KEY_TAB': 9,
'KEY_CLEAR': 12,
'KEY_ENTER': 13,
'KEY_...': 14,
'KEY_SHIFT': 16,
'KEY_CONTROL': 17,
'KEY_ALT': 18,
'KEY_PAUSE': 19,
'KEY_CAPSLOCK': 20,
'KEY_ESC': 27,
'KEY_SPACE': 32,
'KEY_PAGEUP': 33,
'KEY_PAGEDOWN': 34,
'KEY_END': 35,
'KEY_HOME': 36,
'KEY_LEFT': 37,
'KEY_UP': 38,
'KEY_RIGHT': 39,
'KEY_DOWN': 40,
'KEY_PRINTSCREEN': 44,
'KEY_INSERT': 45,
'KEY_DELETE': 46,
'KEY_0': 48,
'KEY_1': 49,
'KEY_2': 50,
'KEY_3': 51,
'KEY_4': 52,
'KEY_5': 53,
'KEY_6': 54,
'KEY_7': 55,
'KEY_8': 56,
'KEY_9': 57,
'KEY_SEMICOLON': 59,
'KEY_EQUAL': 61,
'KEY_A': 65,
'KEY_B': 66,
'KEY_C': 67,
'KEY_D': 68,
'KEY_E': 69,
'KEY_F': 70,
'KEY_G': 71,
'KEY_H': 72,
'KEY_I': 73,
'KEY_J': 74,
'KEY_K': 75,
'KEY_L': 76,
'KEY_M': 77,
'KEY_N': 78,
'KEY_O': 79,
'KEY_P': 80,
'KEY_Q': 81,
'KEY_R': 82,
'KEY_S': 83,
'KEY_T': 84,
'KEY_U': 85,
'KEY_V': 86,
'KEY_W': 87,
'KEY_X': 88,
'KEY_Y': 89,
'KEY_Z': 90,
'KEY_CONTEXTMENU': 93,
'KEY_NP0': 96,
'KEY_NP1': 97,
'KEY_NP2': 98,
'KEY_NP3': 99,
'KEY_NP4': 100,
'KEY_NP5': 101,
'KEY_NP6': 102,
'KEY_NP7': 103,
'KEY_NP8': 104,
'KEY_NP9': 105,
'KEY_KPASTERISK': 106,
'KEY_KPPLUS': 107,
'KEY_SEPARATOR': 108,
'KEY_KPMINUS': 109,
'KEY_KPDOT': 110,
'KEY_KPSLASH': 111,
'KEY_F1': 112,
'KEY_F2': 113,
'KEY_F3': 114,
'KEY_F4': 115,
'KEY_F5': 116,
'KEY_F6': 117,
'KEY_F7': 118,
'KEY_F8': 119,
'KEY_F9': 120,
'KEY_F10': 121,
'KEY_F11': 122,
'KEY_F12': 123,
'KEY_F13': 124,
'KEY_F14': 125,
'KEY_F15': 126,
'KEY_F16': 127,
'KEY_F17': 128,
'KEY_F18': 129,
'KEY_F19': 130,
'KEY_F20': 131,
'KEY_F21': 132,
'KEY_F22': 133,
'KEY_F23': 134,
'KEY_F24': 135,
'KEY_NUMLOCK': 144,
'KEY_SCROLLLOCK': 145,
'KEY_FIND': 170,
'KEY_COMMA': 188,
'KEY_MINUS': 189,
'KEY_DOT': 190,
'KEY_SLASH': 191,
'KEY_GRAVE': 192,
'KEY_LEFTBRACE': 219,
'KEY_BACKSLASH': 220,
'KEY_RIGHTBRACE': 221,
'KEY_APOSTROPHE': 222,
'KEY_META': 224
} }

1
runhidinput.sh Executable file
View File

@@ -0,0 +1 @@
uwsgi --http [::]:8001 --gevent 1000 --http-websockets --master --wsgi-file hidinput.py --callable app

1
runsockettest.sh Executable file
View File

@@ -0,0 +1 @@
uwsgi --http :8001 --gevent 1000 --http-websockets --master --wsgi-file socketiotest.py --callable app

19
socketiotest.py Normal file
View File

@@ -0,0 +1,19 @@
from flask import Flask, render_template
from flask_socketio import SocketIO
app = Flask(__name__)
socketio = SocketIO(app)
@app.route("/")
def index():
return render_template("socketio.html")
@socketio.on('my event')
def handle_my_custom_event(json):
print('received json: ' + str(json))
if __name__ == '__main__':
socketio.run(host="0.0.0.0", port=8001, app=app)

View File

@@ -6,76 +6,110 @@
<style> <style>
</style> </style>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script> <script src="https://code.jquery.com/jquery-3.5.0.js"></script>
</head> <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<body> <script>
HID input service, POST data to /keyboard or /mouse <br/> function zapis(t) {
<div> $("div").text(t);
</div> }
<br/> var previous;
Server response: <span></span>
<script> $(window).bind('keydown', function(event) {
function zapis(t) { event.preventDefault();
$("div").text(t); var str = String.fromCharCode(event.which).toLowerCase();
}
var previous; var ctrl = event.ctrlKey;
if (previous == 17) {
ctrl = true;
}
$(window).bind('keydown', function(event) { var obj = {
event.preventDefault(); ctrlKey: ctrl,
var str = String.fromCharCode(event.which).toLowerCase(); shiftKey: event.shiftKey,
altKey: event.altKey,
which: event.which,
code: event.code,
str: str
}
var ctrl = event.ctrlKey; if (event.which != 16 && event.which != 17 && event.which != 18) {
if (previous == 17) { console.log(obj);
ctrl = true;
}
var obj = { var ret = $.ajax({
ctrlKey: ctrl, type: "POST",
shiftKey: event.shiftKey, url: "hid/keyboard",
altKey: event.altKey, data: JSON.stringify(obj),
which: event.which, contentType: "application/json; charset=utf-8",
code: event.code, dataType: "json"
str: str });
}
if (event.which != 16 && event.which != 17 && event.which != 18) { console.log(ret);
console.log(obj); }
var ret = $.ajax({ var text = "";
type: "POST", if (ctrl) {
url: "hid/keyboard", text = text + ' + Control';
data: JSON.stringify(obj), }
contentType: "application/json; charset=utf-8", if (event.shiftKey) {
dataType: "json" text = text + ' + Shift';
}
if (event.altKey) {
text = text + ' + Alt';
}
text = text + ' + ' + str;
text = text.substr(3);
zapis(text);
previous = event.keyCode;
});
var btn=0;
var posX=0;
var posY=0;
var wheel=0;
var socket = io();
$(document).ready(function(){
$("canvas").mousedown(function(event){
btn=event.buttons;
handleMouse();
});
$("canvas").mouseup(function(event){
btn=event.buttons;
handleMouse();
});
$("canvas").mousemove(function(event){
posX=event.offsetX;
posY=event.offsetY;
handleMouse();
});
}); });
$("span").text(ret.responseText); function handleMouse() {
console.log(ret); $("span").text(btn +", "+ posX + ", " + posY);
sendMouse(btn, posX, posY, wheel);
}
function sendMouse(btn, x, y) {
var obj = {
x: x,
y: y,
btn: btn,
wheel: wheel,
}
} socket.emit('mouseEvent', JSON.stringify(obj));
};
</script>
</head>
<body>
HID Remote Keyboard and mouse<br/>
var text = ""; <div></div>
if (ctrl) {
text = text + ' + Control';
}
if (event.shiftKey) {
text = text + ' + Shift';
}
if (event.altKey) {
text = text + ' + Alt';
}
text = text + ' + ' + str;
text = text.substr(3);
zapis(text);
previous = event.keyCode;
});
</script>
<span></span><br/><br/>
<canvas width=1920 height=1080 style="border: 1px solid black" oncontextmenu="return false" onwheel='wheel=event.deltaY*-1; handleMouse(); wheel=0; return false;' ></canvas>
</body> </body>
</html> </html>

74
templates/keyboard.html Normal file
View File

@@ -0,0 +1,74 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Klávesnice remote SSH</title>
<style>
</style>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
</head>
<body>
HID input keyboard, POST data to /keyboard<br/>
<div>
</div>
<br/>
Server response: <span></span>
<script>
var socket = io();
function zapis(t) {
$("div").text(t);
}
var previous;
$(window).bind('keydown', function(event) {
event.preventDefault();
var str = String.fromCharCode(event.which).toLowerCase();
var ctrl = event.ctrlKey;
if (previous == 17) {
ctrl = true;
}
var obj = {
ctrlKey: ctrl,
shiftKey: event.shiftKey,
altKey: event.altKey,
which: event.which,
code: event.code,
str: str
}
if (event.which != 16 && event.which != 17 && event.which != 18) {
console.log(obj);
socket.emit('kbdEvent', JSON.stringify(obj));
}
var text = "";
if (ctrl) {
text = text + ' + Control';
}
if (event.shiftKey) {
text = text + ' + Shift';
}
if (event.altKey) {
text = text + ' + Alt';
}
text = text + ' + ' + str;
text = text.substr(3);
zapis(text);
previous = event.keyCode;
});
</script>
</body>
</html>

107
templates/kvm.html Normal file
View File

@@ -0,0 +1,107 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Raspberry Pi KVM</title>
<style>
</style>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script>
var socket = io();
var previous;
$(window).bind('keydown', function(event) {
event.preventDefault();
var str = String.fromCharCode(event.which).toLowerCase();
var ctrl = event.ctrlKey;
if (previous == 17) {
ctrl = true;
}
var obj = {
ctrlKey: ctrl,
shiftKey: event.shiftKey,
altKey: event.altKey,
which: event.which,
code: event.code,
str: str
}
if (event.which != 16 && event.which != 17 && event.which != 18) {
console.log(obj);
socket.emit('kbdEvent', JSON.stringify(obj));
}
var text = "";
if (ctrl) {
text = text + ' + Control';
}
if (event.shiftKey) {
text = text + ' + Shift';
}
if (event.altKey) {
text = text + ' + Alt';
}
text = text + ' + ' + str;
text = text.substr(3);
previous = event.keyCode;
});
var btn=0;
var posX=0;
var posY=0;
var wheel=0;
$(document).ready(function(){
$("img").mousedown(function(event){
btn=event.buttons;
handleMouse();
});
$("img").mouseup(function(event){
btn=event.buttons;
handleMouse();
});
$("img").mousemove(function(event){
posX=event.offsetX;
posY=event.offsetY;
handleMouse();
});
});
function handleMouse() {
$("span").text(btn +", "+ posX + ", " + posY);
sendMouse(btn, posX, posY, wheel);
}
function sendMouse(btn, x, y) {
var obj = {
x: x,
y: y,
btn: btn,
wheel: wheel,
}
var data = new Array(4);
data[0] = btn;
data[1] = x;
data[2] = y;
data[3] = wheel;
//socket.emit('mouseEvent', JSON.stringify(obj));
socket.emit('mouseEventRaw', data);
};
</script>
</head>
<body>
KVM<br/>
<span></span><br/><br/>
<img src="http://[2a01:510:d501:2800:1b8f:607e:9885:99c7]:8000/video_feed" draggable=false width=1920 height=1080 style="border: 1px solid black" oncontextmenu="return false" onwheel='wheel=event.deltaY*-1; handleMouse(); wheel=0; return false;' >
</body>
</html>

View File

@@ -6,40 +6,57 @@
<style> <style>
</style> </style>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script> <script src="https://code.jquery.com/jquery-3.5.0.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
</head> </head>
<body> <body>
HID mouse service, POST data to /mouse <br/> HID mouse service, POST data to /mouse <br/>
<div> <div>
</div> </div>
<input type="button" onclick="sendMouse(0, 0, -10);" value="^" />
<input type="button" onclick="sendMouse(0, -10, 0);" value="<" />
<input type="button" onclick="sendMouse(0, 10, 0);" value=">" />
<input type="button" onclick="sendMouse(0, 0, 10);" value="v" /><br />
<input type="button" onclick="sendMouse(1, 0, 0);" value="LEFT" />
<input type="button" onclick="sendMouse(2, 0, 0);" value="RIGHT" />
<script> <script>
var btn=0;
var posX=0;
var posY=0;
var wheel=0;
var socket = io();
$(document).ready(function(){
$("canvas").mousedown(function(event){
btn=event.buttons;
handleMouse();
});
$("canvas").mouseup(function(event){
btn=event.buttons;
handleMouse();
});
$("canvas").mousemove(function(event){
posX=event.offsetX;
posY=event.offsetY;
handleMouse();
});
});
function handleMouse() {
$("span").text(btn +", "+ posX + ", " + posY);
sendMouse(btn, posX, posY, wheel);
}
function sendMouse(btn, x, y) { function sendMouse(btn, x, y) {
var obj = { var obj = {
x: x, x: x,
y: y, y: y,
btn: btn, btn: btn,
wheel: 0, wheel: wheel,
} }
var ret = $.ajax({ socket.emit('mouseEvent', JSON.stringify(obj));
type: "POST",
url: "hid/mouse",
data: JSON.stringify(obj),
contentType: "application/json; charset=utf-8",
dataType: "json"
});
}; };
</script> </script>
<span></span><br/><br/>
<canvas width=1920 height=1080 style="border: 1px solid black" oncontextmenu="return false" onwheel='wheel=event.deltaY*-1; handleMouse(); wheel=0; return false;' ></canvas>
<!--<img src="placeholder.png" width=1920 height=1080 onmousemove='console.log("aaa");' />-->
</body> </body>
</html> </html>

14
templates/socketio.html Normal file
View File

@@ -0,0 +1,14 @@
<html>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on('connect', function() {
socket.emit('my event', {data: 'I\'m connected!'});
});
</script>
ahoj3
<input type="button" onClick="socket.emit('my event', 'test');" value="test" />
</body>
</html>

View File

@@ -4,7 +4,6 @@ from flask import render_template
import threading import threading
import argparse import argparse
import datetime import datetime
import imutils
import time import time
import cv2 import cv2
from hashlib import md5 from hashlib import md5
@@ -27,77 +26,77 @@ time.sleep(1.0)
@app.route("/") @app.route("/")
def index(): def index():
# return the rendered template # return the rendered template
return render_template("index.html") return render_template("index.html")
def detect_motion(frameCount): def detect_motion(frameCount):
global vs, outputFrame, lock global vs, outputFrame, lock
lastframe = None lastframe = None
while True: while True:
flag, frame = cap.read() flag, frame = cap.read()
framedig = md5(frame).digest() framedig = md5(frame).digest()
if lastframe == framedig: if lastframe == framedig:
print("Duplicate frame, skipping") print("Duplicate frame, skipping")
continue continue
if not flag: if not flag:
continue continue
lastframe = framedig lastframe = framedig
timestamp = datetime.datetime.now() timestamp = datetime.datetime.now()
cv2.putText(frame, timestamp.strftime( cv2.putText(frame, timestamp.strftime(
"%A %d %B %Y %I:%M:%S%p"), (10, 15), "%A %d %B %Y %I:%M:%S%p"), (10, 15),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 1) cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 1)
with lock:
outputFrame = frame.copy()
with lock:
outputFrame = frame.copy()
def generate(): def generate():
global outputFrame, lock global outputFrame, lock
while True: while True:
with lock: with lock:
if outputFrame is None: if outputFrame is None:
continue continue
(flag, encodedImage) = cv2.imencode(".jpg", outputFrame) (flag, encodedImage) = cv2.imencode(".jpg", outputFrame)
# ensure the frame was successfully encoded # ensure the frame was successfully encoded
if not flag: if not flag:
continue continue
# yield the output frame in the byte format # yield the output frame in the byte format
yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
bytearray(encodedImage) + b'\r\n') bytearray(encodedImage) + b'\r\n')
time.sleep(0.2) time.sleep(0.2)
@app.route("/video_feed") @app.route("/video_feed")
def video_feed(): def video_feed():
# return the response generated along with the specific media # return the response generated along with the specific media
# type (mime type) # type (mime type)
return Response(generate(), return Response(generate(),
mimetype = "multipart/x-mixed-replace; boundary=frame") mimetype = "multipart/x-mixed-replace; boundary=frame")
# check to see if this is the main thread of execution # check to see if this is the main thread of execution
if __name__ == '__main__': if __name__ == '__main__':
# construct the argument parser and parse command line arguments # construct the argument parser and parse command line arguments
ap = argparse.ArgumentParser() ap = argparse.ArgumentParser()
ap.add_argument("-i", "--ip", type=str, required=True, ap.add_argument("-i", "--ip", type=str, required=True,
help="ip address of the device") help="ip address of the device")
ap.add_argument("-o", "--port", type=int, required=True, ap.add_argument("-o", "--port", type=int, required=True,
help="ephemeral port number of the server (1024 to 65535)") help="ephemeral port number of the server (1024 to 65535)")
ap.add_argument("-f", "--frame-count", type=int, default=32, ap.add_argument("-f", "--frame-count", type=int, default=32,
help="# of frames used to construct the background model") help="# of frames used to construct the background model")
args = vars(ap.parse_args()) args = vars(ap.parse_args())
# start a thread that will perform motion detection # start a thread that will perform motion detection
t = threading.Thread(target=detect_motion, args=( t = threading.Thread(target=detect_motion, args=(
args["frame_count"],)) args["frame_count"],))
t.daemon = True t.daemon = True
t.start() t.start()
# start the flask app # start the flask app
app.run(host=args["ip"], port=args["port"], debug=True, app.run(host=args["ip"], port=args["port"], debug=True,
threaded=True, use_reloader=False) threaded=True, use_reloader=False)