forked from Mqrius/BluePloverPi
-
Notifications
You must be signed in to change notification settings - Fork 1
/
PiTooth.py
executable file
·160 lines (141 loc) · 5.13 KB
/
PiTooth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/env python
#Code fixed from http://www.linuxuser.co.uk/tutorials/emulate-a-bluetooth-keyboard-with-the-raspberry-pi
# Updated to work with Bluez 5
import os
import sys
import bluetooth
from bluetooth import *
import dbus
import time
import evdev
from evdev import *
import keymap
import uuid
BT_ADAPTER_PATH="/org/bluez/hci0"
BT_UUID = str(uuid.uuid4())
class Bluetooth:
P_CTRL = 17
P_INTR = 19
HOST = 0
PORT = 1
def __init__(self):
self.scontrol = BluetoothSocket(L2CAP)
self.sinterrupt = BluetoothSocket(L2CAP)
self.scontrol.bind(("", Bluetooth.P_CTRL))
self.sinterrupt.bind(("", Bluetooth.P_INTR))
self.bus = dbus.SystemBus()
adapter = dbus.Interface(self.bus.get_object("org.bluez", BT_ADAPTER_PATH),
"org.freedesktop.DBus.Properties")
# The Name and Class of a device should be statically configured
# according to the Bluez dbus interface docs. These are set
# in /etc/bluetooth/main.conf
adapter.Set("org.bluez.Adapter1", "Alias", "Raspberry Pi")
adapter.Set("org.bluez.Adapter1", "Powered", dbus.Boolean(1))
adapter.Set("org.bluez.Adapter1", "PairableTimeout", dbus.UInt32(0))
adapter.Set("org.bluez.Adapter1", "Pairable", dbus.Boolean(1))
adapter.Set("org.bluez.Adapter1", "DiscoverableTimeout", dbus.UInt32(0))
adapter.Set("org.bluez.Adapter1", "Discoverable", dbus.Boolean(1))
# Register the SDP defined in the XML file
self.manager = dbus.Interface(self.bus.get_object("org.bluez",
"/org/bluez"), "org.bluez.ProfileManager1")
with open(sys.path[0] + "/sdp_record.xml", "r") as fh:
self.service_record = fh.read()
def listen(self):
profile = {
"ServiceRecord" : self.service_record,
}
# Register our device profile
self.manager.RegisterProfile(BT_ADAPTER_PATH, BT_UUID, profile)
print "Service record added"
self.scontrol.listen(1) # Limit of 1 connection
self.sinterrupt.listen(1)
print "Waiting for a connection"
self.ccontrol, self.cinfo = self.scontrol.accept()
print "Got a connection on the control channel from " + self.cinfo[Bluetooth.HOST]
self.cinterrupt, self.cinfo = self.sinterrupt.accept()
print "Got a connection on the interrupt channel fro " + self.cinfo[Bluetooth.HOST]
def send_input(self, ir):
# Convert the hex array to a string
hex_str = ""
for element in ir:
if type(element) is list:
# This is our bit array - convrt it to a single byte represented
# as a char
bin_str = ""
for bit in element:
bin_str += str(bit)
hex_str += chr(int(bin_str, 2))
else:
# This is a hex value - we can convert it straight to a char
hex_str += chr(element)
# Send an input report
self.cinterrupt.send(hex_str)
class Keyboard():
def __init__(self):
# The structure for an bt keyboard input report (size is 10 bytes)
self.state = [
0xA1, # This is an input report
0x01, # Usage report = Keyboard
# Bit array for Modifier keys
[0, # Right GUI - (usually the Windows key)
0, # Right ALT
0, # Right Shift
0, # Right Control
0, # Left GUI - (again, usually the Windows key)
0, # Left ALT
0, # Left Shift
0], # Left Control
0x00, # Vendor reserved
0x00, # Rest is space for 6 keys
0x00,
0x00,
0x00,
0x00,
0x00 ]
# Keep trying to get a keyboard
have_dev = False
while have_dev == False:
try:
# Try and get a keyboard - should always be event0 as we.re only
# plugging one thing in
self.dev = InputDevice("/dev/input/event0")
have_dev = True
except OSError:
print "Keyboard not found, waiting 3 seconds and retrying"
time.sleep(3)
print "Found a keyboard"
def change_state(self, event):
evdev_code = ecodes.KEY[event.code]
modkey_element = keymap.modkey(evdev_code)
if modkey_element > 0:
# Need to set one of the modifier bits
if self.state[2][modkey_element] == 0:
self.state[2][modkey_element] = 1
else:
self.state[2][modkey_element] = 0
else:
# Get the hex keycode of the key
hex_key = keymap.convert(evdev_code)
# Loop through elements 4 to 9 of the input report structure
for i in range (4, 10):
if self.state[i] == hex_key and event.value == 0:
# Code is 0 so we need to depress it
self.state[i] = 0x00
break
elif self.state[i] == 0x00 and event.value == 1:
# If the current space is empty and the key is being pressed
self.state[i] = hex_key
break
def event_loop(self, bt):
for event in self.dev.read_loop():
# Only bother if we hit a key and it's an up or down event
if event.type == ecodes.EV_KEY and event.value < 2:
self.change_state(event)
bt.send_input(self.state)
if __name__ == "__main__":
if not os.geteuid() == 0:
sys.exit("Only root can run this script")
bt = Bluetooth()
bt.listen()
kb = Keyboard()
kb.event_loop(bt)