10
10
#include <notification/notification.h>
11
11
#include <notification/notification_messages.h>
12
12
13
+ typedef struct ButtonEvent {
14
+ int8_t button ;
15
+ bool state ;
16
+ } ButtonEvent ;
17
+
18
+ #define BTN_EVT_QUEUE_SIZE 32
19
+
13
20
struct BtMouse {
14
21
View * view ;
15
22
ViewDispatcher * view_dispatcher ;
16
23
Bt * bt ;
17
24
NotificationApp * notifications ;
25
+ FuriMutex * mutex ;
26
+ FuriThread * thread ;
27
+ bool connected ;
28
+
29
+ // Current mouse state
30
+ uint8_t btn ;
31
+ int dx ;
32
+ int dy ;
33
+ int wheel ;
34
+
35
+ // Circular buffer;
36
+ // (qhead == qtail) means either empty or overflow.
37
+ // We'll ignore overflow and treat it as empty.
38
+ int qhead ;
39
+ int qtail ;
40
+ ButtonEvent queue [BTN_EVT_QUEUE_SIZE ];
18
41
};
19
42
43
+ #define BT_MOUSE_FLAG_INPUT_EVENT (1UL << 0)
44
+ #define BT_MOUSE_FLAG_KILL_THREAD (1UL << 1)
45
+ #define BT_MOUSE_FLAG_ALL (BT_MOUSE_FLAG_INPUT_EVENT | BT_MOUSE_FLAG_KILL_THREAD)
46
+
20
47
#define MOUSE_MOVE_SHORT 5
21
48
#define MOUSE_MOVE_LONG 20
22
49
50
+ static void bt_mouse_notify_event (BtMouse * bt_mouse ) {
51
+ FuriThreadId thread_id = furi_thread_get_id (bt_mouse -> thread );
52
+ furi_assert (thread_id );
53
+ furi_thread_flags_set (thread_id , BT_MOUSE_FLAG_INPUT_EVENT );
54
+ }
55
+
23
56
static void bt_mouse_draw_callback (Canvas * canvas , void * context ) {
24
57
UNUSED (context );
25
58
canvas_clear (canvas );
@@ -29,6 +62,20 @@ static void bt_mouse_draw_callback(Canvas* canvas, void* context) {
29
62
canvas_draw_str (canvas , 0 , 63 , "Hold [back] to exit" );
30
63
}
31
64
65
+ static void bt_mouse_button_state (BtMouse * bt_mouse , int8_t button , bool state ) {
66
+ ButtonEvent event ;
67
+ event .button = button ;
68
+ event .state = state ;
69
+
70
+ if (bt_mouse -> connected ) {
71
+ furi_mutex_acquire (bt_mouse -> mutex , FuriWaitForever );
72
+ bt_mouse -> queue [bt_mouse -> qtail ++ ] = event ;
73
+ bt_mouse -> qtail %= BTN_EVT_QUEUE_SIZE ;
74
+ furi_mutex_release (bt_mouse -> mutex );
75
+ bt_mouse_notify_event (bt_mouse );
76
+ }
77
+ }
78
+
32
79
static void bt_mouse_process (BtMouse * bt_mouse , InputEvent * event ) {
33
80
with_view_model (
34
81
bt_mouse -> view ,
@@ -37,21 +84,21 @@ static void bt_mouse_process(BtMouse* bt_mouse, InputEvent* event) {
37
84
UNUSED (model );
38
85
if (event -> key == InputKeyUp ) {
39
86
if (event -> type == InputTypePress ) {
40
- furi_hal_bt_hid_mouse_press ( HID_MOUSE_BTN_LEFT );
87
+ bt_mouse_button_state ( bt_mouse , HID_MOUSE_BTN_LEFT , true );
41
88
} else if (event -> type == InputTypeRelease ) {
42
- furi_hal_bt_hid_mouse_release ( HID_MOUSE_BTN_LEFT );
89
+ bt_mouse_button_state ( bt_mouse , HID_MOUSE_BTN_LEFT , false );
43
90
}
44
91
} else if (event -> key == InputKeyDown ) {
45
92
if (event -> type == InputTypePress ) {
46
- furi_hal_bt_hid_mouse_press ( HID_MOUSE_BTN_RIGHT );
93
+ bt_mouse_button_state ( bt_mouse , HID_MOUSE_BTN_RIGHT , true );
47
94
} else if (event -> type == InputTypeRelease ) {
48
- furi_hal_bt_hid_mouse_release ( HID_MOUSE_BTN_RIGHT );
95
+ bt_mouse_button_state ( bt_mouse , HID_MOUSE_BTN_RIGHT , false );
49
96
}
50
97
} else if (event -> key == InputKeyOk ) {
51
98
if (event -> type == InputTypePress ) {
52
- furi_hal_bt_hid_mouse_press ( HID_MOUSE_BTN_WHEEL );
99
+ bt_mouse_button_state ( bt_mouse , HID_MOUSE_BTN_WHEEL , true );
53
100
} else if (event -> type == InputTypeRelease ) {
54
- furi_hal_bt_hid_mouse_release ( HID_MOUSE_BTN_WHEEL );
101
+ bt_mouse_button_state ( bt_mouse , HID_MOUSE_BTN_WHEEL , false );
55
102
}
56
103
}
57
104
},
@@ -77,17 +124,35 @@ void bt_mouse_connection_status_changed_callback(BtStatus status, void* context)
77
124
furi_assert (context );
78
125
BtMouse * bt_mouse = context ;
79
126
80
- bool connected = (status == BtStatusConnected );
81
- if (connected ) {
127
+ bt_mouse -> connected = (status == BtStatusConnected );
128
+ if (bt_mouse -> connected ) {
82
129
notification_internal_message (bt_mouse -> notifications , & sequence_set_blue_255 );
130
+ tracking_begin ();
131
+ view_dispatcher_send_custom_event (bt_mouse -> view_dispatcher , 0 );
83
132
} else {
133
+ tracking_end ();
84
134
notification_internal_message (bt_mouse -> notifications , & sequence_reset_blue );
85
135
}
86
136
87
137
//with_view_model(
88
138
// bt_mouse->view, void * model, { model->connected = connected; }, true);
89
139
}
90
140
141
+ bool bt_mouse_move (int8_t dx , int8_t dy , void * context ) {
142
+ furi_assert (context );
143
+ BtMouse * bt_mouse = context ;
144
+
145
+ if (bt_mouse -> connected ) {
146
+ furi_mutex_acquire (bt_mouse -> mutex , FuriWaitForever );
147
+ bt_mouse -> dx += dx ;
148
+ bt_mouse -> dy += dy ;
149
+ furi_mutex_release (bt_mouse -> mutex );
150
+ bt_mouse_notify_event (bt_mouse );
151
+ }
152
+
153
+ return true;
154
+ }
155
+
91
156
void bt_mouse_enter_callback (void * context ) {
92
157
furi_assert (context );
93
158
BtMouse * bt_mouse = context ;
@@ -98,18 +163,15 @@ void bt_mouse_enter_callback(void* context) {
98
163
bt_mouse -> bt , bt_mouse_connection_status_changed_callback , bt_mouse );
99
164
furi_assert (bt_set_profile (bt_mouse -> bt , BtProfileHidKeyboard ));
100
165
furi_hal_bt_start_advertising ();
101
-
102
- tracking_begin ();
103
-
104
- view_dispatcher_send_custom_event (bt_mouse -> view_dispatcher , 0 );
105
166
}
106
167
107
168
bool bt_mouse_custom_callback (uint32_t event , void * context ) {
108
169
UNUSED (event );
109
170
furi_assert (context );
110
171
BtMouse * bt_mouse = context ;
111
172
112
- tracking_step (furi_hal_bt_hid_mouse_move );
173
+ tracking_step (bt_mouse_move , context );
174
+ furi_delay_ms (3 ); // Magic! Removing this will break the buttons
113
175
114
176
view_dispatcher_send_custom_event (bt_mouse -> view_dispatcher , 0 );
115
177
return true;
@@ -120,7 +182,6 @@ void bt_mouse_exit_callback(void* context) {
120
182
BtMouse * bt_mouse = context ;
121
183
122
184
tracking_end ();
123
-
124
185
notification_internal_message (bt_mouse -> notifications , & sequence_reset_blue );
125
186
126
187
furi_hal_bt_stop_advertising ();
@@ -132,8 +193,91 @@ void bt_mouse_exit_callback(void* context) {
132
193
bt_mouse -> bt = NULL ;
133
194
}
134
195
196
+ static int8_t clamp (int t ) {
197
+ if (t < -128 ) {
198
+ return -128 ;
199
+ }
200
+ else if (t > 127 ) {
201
+ return 127 ;
202
+ }
203
+ return t ;
204
+ }
205
+
206
+ static int32_t bt_mouse_thread_callback (void * context ) {
207
+ furi_assert (context );
208
+ BtMouse * bt_mouse = (BtMouse * )context ;
209
+
210
+ while (1 ) {
211
+ uint32_t flags = furi_thread_flags_wait (BT_MOUSE_FLAG_ALL , FuriFlagWaitAny , FuriWaitForever );
212
+ if (flags & BT_MOUSE_FLAG_KILL_THREAD ) {
213
+ break ;
214
+ }
215
+ if (flags & BT_MOUSE_FLAG_INPUT_EVENT ) {
216
+ furi_mutex_acquire (bt_mouse -> mutex , FuriWaitForever );
217
+
218
+ ButtonEvent event ;
219
+ bool send_buttons = false;
220
+ if (bt_mouse -> qhead != bt_mouse -> qtail ) {
221
+ event = bt_mouse -> queue [bt_mouse -> qhead ++ ];
222
+ bt_mouse -> qhead %= BTN_EVT_QUEUE_SIZE ;
223
+ send_buttons = true;
224
+ }
225
+
226
+ int8_t dx = clamp (bt_mouse -> dx );
227
+ bt_mouse -> dx -= dx ;
228
+ int8_t dy = clamp (bt_mouse -> dy );
229
+ bt_mouse -> dy -= dy ;
230
+ int8_t wheel = clamp (bt_mouse -> wheel );
231
+ bt_mouse -> wheel -= wheel ;
232
+
233
+ furi_mutex_release (bt_mouse -> mutex );
234
+
235
+ if (bt_mouse -> connected && send_buttons ) {
236
+ if (event .state ) {
237
+ furi_hal_bt_hid_mouse_press (event .button );
238
+ } else {
239
+ furi_hal_bt_hid_mouse_release (event .button );
240
+ }
241
+ }
242
+
243
+ if (bt_mouse -> connected && (dx != 0 || dy != 0 )) {
244
+ furi_hal_bt_hid_mouse_move (dx , dy );
245
+ }
246
+
247
+ if (bt_mouse -> connected && wheel != 0 ) {
248
+ furi_hal_bt_hid_mouse_scroll (wheel );
249
+ }
250
+ }
251
+ }
252
+
253
+ return 0 ;
254
+ }
255
+
256
+ void bt_mouse_thread_start (BtMouse * bt_mouse ) {
257
+ furi_assert (bt_mouse );
258
+ bt_mouse -> mutex = furi_mutex_alloc (FuriMutexTypeNormal );
259
+ bt_mouse -> thread = furi_thread_alloc ();
260
+ furi_thread_set_name (bt_mouse -> thread , "BtSender" );
261
+ furi_thread_set_stack_size (bt_mouse -> thread , 1024 );
262
+ furi_thread_set_context (bt_mouse -> thread , bt_mouse );
263
+ furi_thread_set_callback (bt_mouse -> thread , bt_mouse_thread_callback );
264
+ furi_thread_start (bt_mouse -> thread );
265
+ }
266
+
267
+ void bt_mouse_thread_stop (BtMouse * bt_mouse ) {
268
+ furi_assert (bt_mouse );
269
+ FuriThreadId thread_id = furi_thread_get_id (bt_mouse -> thread );
270
+ furi_assert (thread_id );
271
+ furi_thread_flags_set (thread_id , BT_MOUSE_FLAG_KILL_THREAD );
272
+ furi_thread_join (bt_mouse -> thread );
273
+ furi_thread_free (bt_mouse -> thread );
274
+ furi_mutex_free (bt_mouse -> mutex );
275
+ }
276
+
135
277
BtMouse * bt_mouse_alloc (ViewDispatcher * view_dispatcher ) {
136
278
BtMouse * bt_mouse = malloc (sizeof (BtMouse ));
279
+ memset (bt_mouse , 0 , sizeof (BtMouse ));
280
+
137
281
bt_mouse -> view = view_alloc ();
138
282
bt_mouse -> view_dispatcher = view_dispatcher ;
139
283
view_set_context (bt_mouse -> view , bt_mouse );
@@ -142,11 +286,13 @@ BtMouse* bt_mouse_alloc(ViewDispatcher* view_dispatcher) {
142
286
view_set_enter_callback (bt_mouse -> view , bt_mouse_enter_callback );
143
287
view_set_custom_callback (bt_mouse -> view , bt_mouse_custom_callback );
144
288
view_set_exit_callback (bt_mouse -> view , bt_mouse_exit_callback );
289
+ bt_mouse_thread_start (bt_mouse );
145
290
return bt_mouse ;
146
291
}
147
292
148
293
void bt_mouse_free (BtMouse * bt_mouse ) {
149
294
furi_assert (bt_mouse );
295
+ bt_mouse_thread_stop (bt_mouse );
150
296
view_free (bt_mouse -> view );
151
297
free (bt_mouse );
152
298
}
0 commit comments