xref: /haiku/src/add-ons/input_server/devices/keyboard/KeyboardInputDevice.cpp (revision 302f62604763c95777d6d04cca456e876f471c4f)
1 /*
2  * Copyright 2004-2006, Jérôme Duval. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "KeyboardInputDevice.h"
7 #include "kb_mouse_driver.h"
8 
9 #include <Directory.h>
10 #include <Entry.h>
11 #include <NodeMonitor.h>
12 #include <Path.h>
13 #include <String.h>
14 
15 #include <errno.h>
16 #include <new>
17 #include <stdlib.h>
18 #include <unistd.h>
19 
20 
21 #if DEBUG
22 FILE *KeyboardInputDevice::sLogFile = NULL;
23 #endif
24 
25 const static uint32 kKeyboardThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
26 const static char *kKeyboardDevicesDirectory = "/dev/input/keyboard";
27 
28 // "/dev/" is automatically prepended by StartMonitoringDevice()
29 const static char *kKeyboardDevicesDirectoryPS2 = "input/keyboard/at";
30 const static char *kKeyboardDevicesDirectoryUSB = "input/keyboard/usb";
31 
32 const static uint32 kATKeycodeMap[] = {
33 	0x1,	// Esc
34 	0x12, 	// 1
35 	0x13,	// 2
36 	0x14,	// 3
37 	0x15,	// 4
38 	0x16,	// 5
39 	0x17,	// 6
40 	0x18,	// 7
41 	0x19,	// 8
42 	0x1a,	// 9
43 	0x1b,	// 0
44 	0x1c,	// -
45 	0x1d,	// =
46 	0x1e,	// BACKSPACE
47 	0x26,	// TAB
48 	0x27,	// Q
49 	0x28,	// W
50 	0x29,	// E
51 	0x2a,	// R
52 	0x2b,	// T
53 	0x2c,	// Y
54 	0x2d,	// U
55 	0x2e,	// I
56 	0x2f,	// O
57 	0x30,	// P
58 	0x31,   // [
59 	0x32,	// ]
60 	0x47,	// ENTER
61 	0x5c,	// Left Control
62 	0x3c,	// A
63 	0x3d,	// S
64 	0x3e,	// D
65 	0x3f,	// F
66 	0x40,	// G
67 	0x41,	// H
68 	0x42,	// J
69 	0x43,	// K
70 	0x44,	// L
71 	0x45,	// ;
72 	0x46,	// '
73 	0x11,	// `
74 	0x4b,	// Left Shift
75 	0x33, 	// \ (backslash -- note: don't remove non-white-space after BS char)
76 	0x4c,	// Z
77 	0x4d,	// X
78 	0x4e,	// C
79 	0x4f,	// V
80 	0x50,	// B
81 	0x51,	// N
82 	0x52,	// M
83 	0x53,	// ,
84 	0x54,	// .
85 	0x55,	// /
86 	0x56,	// Right Shift
87 	0x24,	// *
88 	0x5d,	// Left Alt
89 	0x5e,	// Space
90 	0x3b,	// Caps
91 	0x02,	// F1
92 	0x03,	// F2
93 	0x04,	// F3
94 	0x05,	// F4
95 	0x06,	// F5
96 	0x07,	// F6
97 	0x08,	// F7
98 	0x09,	// F8
99 	0x0a,	// F9
100 	0x0b,	// F10
101 	0x22,	// Num
102 	0x0f,	// Scroll
103 	0x37,	// KP 7
104 	0x38,	// KP 8
105 	0x39,	// KP 9
106 	0x25,	// KP -
107 	0x48,	// KP 4
108 	0x49,	// KP 5
109 	0x4a,	// KP 6
110 	0x3a,	// KP +
111 	0x58,	// KP 1
112 	0x59,	// KP 2
113 	0x5a,	// KP 3
114 	0x64,	// KP 0
115 	0x65,	// KP .
116 	0x00,	// UNMAPPED
117 	0x00,	// UNMAPPED
118 	0x69,	// <
119 	0x0c,	// F11
120 	0x0d,	// F12
121 	0x00,   // UNMAPPED
122 	0x00,   // UNMAPPED		90
123 	0x00,   // UNMAPPED
124 	0x00,   // UNMAPPED
125 	0x00,   // UNMAPPED
126 	0x00,   // UNMAPPED
127 	0x00,   // UNMAPPED
128 	0x00,   // UNMAPPED
129 	0x00,   // UNMAPPED
130 	0x00,   // UNMAPPED
131 	0x00,   // UNMAPPED
132 	0x00,   // UNMAPPED		100
133 	0x00,   // UNMAPPED
134 	0x00,   // UNMAPPED
135 	0x00,   // UNMAPPED
136 	0x00,   // UNMAPPED
137 	0x00,   // UNMAPPED
138 	0x00,   // UNMAPPED
139 	0x00,   // UNMAPPED
140 	0x00,   // UNMAPPED
141 	0x00,   // UNMAPPED
142 	0x00,   // UNMAPPED		110
143 	0x00,   // UNMAPPED
144 	0x6e,   // Katakana/Hiragana, second key right to spacebar, japanese
145 	0x00,   // UNMAPPED
146 	0x00,   // UNMAPPED
147 	0x6b,   // Ro (\\ key, japanese)
148 	0x00,   // UNMAPPED
149 	0x00,   // UNMAPPED
150 	0x00,   // UNMAPPED
151 	0x00,   // UNMAPPED
152 	0x00,   // UNMAPPED		120
153 	0x6d,   // Henkan, first key right to spacebar, japanese
154 	0x00,   // UNMAPPED
155 	0x6c,   // Muhenkan, key left to spacebar, japanese
156 	0x00,   // UNMAPPED
157 	0x6a,   // Yen (macron key, japanese)
158 	0x70,   // Keypad . on Brazilian ABNT2
159 	0x00,   // UNMAPPED
160 	0x00,   // UNMAPPED
161 	0x00,   // UNMAPPED
162 	0x00,   // UNMAPPED		130
163 	0x00,   // UNMAPPED
164 	0x00,   // UNMAPPED
165 	0x00,   // UNMAPPED
166 	0x00,   // UNMAPPED
167 	0x00,   // UNMAPPED
168 	0x00,   // UNMAPPED
169 	0x00,   // UNMAPPED
170 	0x00,   // UNMAPPED
171 	0x00,   // UNMAPPED
172 	0x00,   // UNMAPPED		140
173 	0x00,   // UNMAPPED
174 	0x00,   // UNMAPPED
175 	0x00,   // UNMAPPED
176 	0x00,   // UNMAPPED
177 	0x00,   // UNMAPPED
178 	0x00,   // UNMAPPED
179 	0x00,   // UNMAPPED
180 	0x00,   // UNMAPPED
181 	0x00,   // UNMAPPED
182 	0x00,   // UNMAPPED		150
183 	0x00,   // UNMAPPED
184 	0x00,   // UNMAPPED
185 	0x00,   // UNMAPPED
186 	0x00,   // UNMAPPED
187 	0x00,   // UNMAPPED
188 	0x5b,   // KP Enter
189 	0x60,   // Right Control
190 	0x00,   // UNMAPPED
191 	0x00,   // UNMAPPED
192 	0x00,   // UNMAPPED		160
193 	0x00,   // UNMAPPED
194 	0x00,   // UNMAPPED
195 	0x00,   // UNMAPPED
196 	0x00,   // UNMAPPED
197 	0x00,   // UNMAPPED
198 	0x00,   // UNMAPPED
199 	0x00,   // UNMAPPED
200 	0x00,   // UNMAPPED
201 	0x00,   // UNMAPPED
202 	0x00,   // UNMAPPED		170
203 	0x00,   // UNMAPPED
204 	0x00,   // UNMAPPED
205 	0x00,   // UNMAPPED
206 	0x00,   // UNMAPPED
207 	0x00,   // UNMAPPED
208 	0x00,   // UNMAPPED
209 	0x00,   // UNMAPPED
210 	0x00,   // UNMAPPED
211 	0x00,   // UNMAPPED
212 	0x00,   // UNMAPPED		180
213 	0x23,   // KP /
214 	0x00,   // UNMAPPED
215 	0x0e,   // Print Screen
216 	0x5f,   // Right Alt
217 	0x00,   // UNMAPPED
218 	0x00,   // UNMAPPED
219 	0x00,   // UNMAPPED
220 	0x00,   // UNMAPPED
221 	0x00,   // UNMAPPED
222 	0x00,   // UNMAPPED		190
223 	0x00,   // UNMAPPED
224 	0x00,   // UNMAPPED
225 	0x00,   // UNMAPPED
226 	0x00,   // UNMAPPED
227 	0x00,   // UNMAPPED
228 	0x00,   // UNMAPPED
229 	0x00,   // UNMAPPED
230 	0x7f,   // Break
231 	0x20,   // Home
232 	0x57,	// Up Arrow		200
233 	0x21,   // Page Up
234 	0x00,   // UNMAPPED
235 	0x61,   // Left Arrow
236 	0x00,   // UNMAPPED
237 	0x63,   // Right Arrow
238 	0x00,   // UNMAPPED
239 	0x35,   // End
240 	0x62,   // Down Arrow
241 	0x36,   // Page Down
242 	0x1f,   // Insert		200
243 	0x34,   // Delete
244 	0x00,   // UNMAPPED
245 	0x00,   // UNMAPPED
246 	0x00,   // UNMAPPED
247 	0x00,   // UNMAPPED
248 	0x00,   // UNMAPPED
249 	0x00,   // UNMAPPED
250 	0x00,   // UNMAPPED
251 	0x66,   // Left Gui
252 	0x67,   // Right Gui	210
253 	0x68,   // Menu
254 	0x00,   // UNMAPPED
255 	0x00,   // UNMAPPED
256 	0x00,   // UNMAPPED
257 	0x00,   // UNMAPPED
258 	0x00,   // UNMAPPED
259 	0x00,   // UNMAPPED
260 	0x00,   // UNMAPPED
261 	0x00,   // UNMAPPED
262 	0x00,   // UNMAPPED		220
263 	0x00,   // UNMAPPED
264 	0x00,   // UNMAPPED
265 	0x00,   // UNMAPPED
266 	0x00,   // UNMAPPED
267 	0x00,   // UNMAPPED
268 	0x00,   // UNMAPPED
269 	0x00,   // UNMAPPED
270 	0x00,   // UNMAPPED
271 	0x00,   // UNMAPPED
272 	0x00,   // UNMAPPED
273 	0x00,   // UNMAPPED
274 	0x00,   // UNMAPPED
275 	0x00,   // UNMAPPED
276 	0x00,   // UNMAPPED
277 	0x00,   // UNMAPPED
278 	0x00,   // UNMAPPED
279 	0x00,   // UNMAPPED
280 	0x00,   // UNMAPPED
281 	0x00,   // UNMAPPED
282 	0x00,   // UNMAPPED
283 	0x00,   // UNMAPPED
284 	0x00,   // UNMAPPED
285 	0x00,   // UNMAPPED
286 	0x00,   // UNMAPPED
287 	0x00,   // UNMAPPED
288 	0x00,   // UNMAPPED
289 	0x00,   // UNMAPPED
290 	0x00,   // UNMAPPED
291 	0x00,   // UNMAPPED
292 	0x00,   // UNMAPPED
293 	0x00,   // UNMAPPED
294 	0x00,   // UNMAPPED
295 	0x00,   // UNMAPPED
296 	0x00,   // UNMAPPED
297 	0x00,   // UNMAPPED
298 	0x00,   // UNMAPPED
299 	0x00,   // UNMAPPED
300 	0x00,   // UNMAPPED
301 	0x00,   // UNMAPPED
302 	0x00,   // UNMAPPED
303 	0x00,   // UNMAPPED
304 	0x00,   // UNMAPPED
305 	0x00,   // UNMAPPED
306 	0x00,   // UNMAPPED
307 	0x00,   // UNMAPPED
308 	0x00,   // UNMAPPED
309 	0x00,   // UNMAPPED
310 	0x00,   // UNMAPPED
311 	0x00,   // UNMAPPED
312 	0x00,   // UNMAPPED
313 	0x00,   // UNMAPPED
314 	0x00,   // UNMAPPED
315 	0x00,   // UNMAPPED
316 	0x00,   // UNMAPPED
317 	0x00,   // UNMAPPED
318 	0x00,   // UNMAPPED
319 	0x00,   // UNMAPPED
320 	0x00,   // UNMAPPED
321 	0x00,   // UNMAPPED
322 	0x00,   // UNMAPPED
323 
324 };
325 
326 
327 extern "C"
328 BInputServerDevice *
329 instantiate_input_device()
330 {
331 	return new (std::nothrow) KeyboardInputDevice();
332 }
333 
334 
335 static char *
336 get_short_name(const char *longName)
337 {
338 	CALLED();
339 	BString string(longName);
340 	BString name;
341 
342 	int32 slash = string.FindLast("/");
343 	string.CopyInto(name, slash + 1, string.Length() - slash);
344 	int32 index = atoi(name.String()) + 1;
345 
346 	int32 previousSlash = string.FindLast("/", slash);
347 	string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1);
348 
349 	// some special handling so that we get "USB" and "AT" instead of "usb"/"at"
350 	if (name.Length() < 4)
351 		name.ToUpper();
352 	else
353 		name.Capitalize();
354 
355 	name << " Keyboard " << index;
356 
357 	return strdup(name.String());
358 }
359 
360 
361 //	#pragma mark -
362 
363 
364 KeyboardInputDevice::KeyboardInputDevice()
365 	: fTMWindow(NULL)
366 {
367 #if DEBUG
368 	if (sLogFile == NULL)
369 		sLogFile = fopen("/var/log/keyboard_device_log.log", "a");
370 #endif
371 	CALLED();
372 
373 	StartMonitoringDevice(kKeyboardDevicesDirectoryPS2);
374 	StartMonitoringDevice(kKeyboardDevicesDirectoryUSB);
375 }
376 
377 
378 KeyboardInputDevice::~KeyboardInputDevice()
379 {
380 	CALLED();
381 	StopMonitoringDevice(kKeyboardDevicesDirectoryUSB);
382 	StopMonitoringDevice(kKeyboardDevicesDirectoryPS2);
383 
384 	int count = fDevices.CountItems();
385 	while (count-- > 0) {
386 		delete (keyboard_device *)fDevices.RemoveItem((int32)0);
387 	}
388 
389 #if DEBUG
390 	fclose(sLogFile);
391 #endif
392 }
393 
394 
395 status_t
396 KeyboardInputDevice::SystemShuttingDown()
397 {
398 	CALLED();
399 	if (fTMWindow)
400 		fTMWindow->PostMessage(SYSTEM_SHUTTING_DOWN);
401 
402 	return B_OK;
403 }
404 
405 
406 status_t
407 KeyboardInputDevice::InitFromSettings(void *cookie, uint32 opcode)
408 {
409 	CALLED();
410 
411 	keyboard_device *device = (keyboard_device *)cookie;
412 
413 	if (opcode == 0 || opcode == B_KEY_REPEAT_RATE_CHANGED) {
414 		if (get_key_repeat_rate(&device->settings.key_repeat_rate) != B_OK)
415 			LOG_ERR("error when get_key_repeat_rate\n");
416 		else if (ioctl(device->fd, KB_SET_KEY_REPEAT_RATE,
417 				&device->settings.key_repeat_rate) != B_OK)
418 			LOG_ERR("error when KB_SET_KEY_REPEAT_RATE, fd:%d\n", device->fd);
419 	}
420 
421 	if (opcode == 0 || opcode == B_KEY_REPEAT_DELAY_CHANGED) {
422 		if (get_key_repeat_delay(&device->settings.key_repeat_delay) != B_OK)
423 			LOG_ERR("error when get_key_repeat_delay\n");
424 		else if (ioctl(device->fd, KB_SET_KEY_REPEAT_DELAY,
425 				&device->settings.key_repeat_delay) != B_OK)
426 			LOG_ERR("error when KB_SET_KEY_REPEAT_DELAY, fd:%d\n", device->fd);
427 	}
428 
429 	if (opcode == 0
430 		|| opcode == B_KEY_MAP_CHANGED
431 		|| opcode == B_KEY_LOCKS_CHANGED) {
432 		fKeymap.LoadCurrent();
433 		device->modifiers = fKeymap.Locks();
434 		SetLeds(device);
435 	}
436 
437 	return B_OK;
438 }
439 
440 
441 status_t
442 KeyboardInputDevice::InitCheck()
443 {
444 	CALLED();
445 	// TODO: this doesn't belong here!
446 	RecursiveScan(kKeyboardDevicesDirectory);
447 
448 	return B_OK;
449 }
450 
451 
452 status_t
453 KeyboardInputDevice::Start(const char *name, void *cookie)
454 {
455 	CALLED();
456 	keyboard_device *device = (keyboard_device *)cookie;
457 
458 	if ((device->fd = open(device->path, O_RDWR)) < B_OK) {
459 		fprintf(stderr, "error when opening %s: %s\n", device->path, strerror(errno));
460 		return B_ERROR;
461 	}
462 
463 	InitFromSettings(device);
464 
465 	char threadName[B_OS_NAME_LENGTH];
466 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", name);
467 
468 	device->active = true;
469 	device->device_watcher = spawn_thread(DeviceWatcher, threadName,
470 		kKeyboardThreadPriority, device);
471 	if (device->device_watcher < B_OK)
472 		return device->device_watcher;
473 
474 	resume_thread(device->device_watcher);
475 	return B_OK;
476 }
477 
478 
479 status_t
480 KeyboardInputDevice::Stop(const char *name, void *cookie)
481 {
482 	CALLED();
483 	keyboard_device *device = (keyboard_device *)cookie;
484 
485 	LOG("Stop(%s)\n", name);
486 
487 	close(device->fd);
488 	device->fd = -1;
489 
490 	device->active = false;
491 	if (device->device_watcher >= 0) {
492 		suspend_thread(device->device_watcher);
493 		resume_thread(device->device_watcher);
494 		status_t dummy;
495 		wait_for_thread(device->device_watcher, &dummy);
496 	}
497 
498 	if (fTMWindow) {
499 		fTMWindow->PostMessage(B_QUIT_REQUESTED);
500 		fTMWindow = NULL;
501 	}
502 
503 	return B_OK;
504 }
505 
506 
507 status_t
508 KeyboardInputDevice::Control(const char *name, void *cookie,
509 	uint32 command, BMessage *message)
510 {
511 	CALLED();
512 	LOG("Control(%s, code: %lu)\n", name, command);
513 
514 	if (command == B_NODE_MONITOR)
515 		HandleMonitor(message);
516 	else if (command >= B_KEY_MAP_CHANGED
517 		&& command <= B_KEY_REPEAT_RATE_CHANGED) {
518 		InitFromSettings(cookie, command);
519 	}
520 	return B_OK;
521 }
522 
523 
524 status_t
525 KeyboardInputDevice::HandleMonitor(BMessage *message)
526 {
527 	CALLED();
528 	int32 opcode = 0;
529 	status_t status;
530 	if ((status = message->FindInt32("opcode", &opcode)) < B_OK)
531 		return status;
532 
533 	if (opcode != B_ENTRY_CREATED
534 		&& opcode != B_ENTRY_REMOVED)
535 		return B_OK;
536 
537 	BEntry entry;
538 	BPath path;
539 	dev_t device;
540 	ino_t directory;
541 	const char *name = NULL;
542 
543 	message->FindInt32("device", &device);
544 	message->FindInt64("directory", &directory);
545 	message->FindString("name", &name);
546 
547 	entry_ref ref(device, directory, name);
548 
549 	if ((status = entry.SetTo(&ref)) != B_OK)
550 		return status;
551 	if ((status = entry.GetPath(&path)) != B_OK)
552 		return status;
553 	if ((status = path.InitCheck()) != B_OK)
554 		return status;
555 
556 	if (opcode == B_ENTRY_CREATED)
557 		AddDevice(path.Path());
558 	else
559 		RemoveDevice(path.Path());
560 
561 	return status;
562 }
563 
564 
565 status_t
566 KeyboardInputDevice::AddDevice(const char *path)
567 {
568 	CALLED();
569 	keyboard_device *device = new (std::nothrow) keyboard_device(path);
570 	if (device == NULL)
571 		return B_NO_MEMORY;
572 
573 	device->fd = -1;
574 	device->device_watcher = -1;
575 	device->active = false;
576 	device->owner = this;
577 	device->isAT = strstr(device->path, "keyboard/at") != NULL;
578 
579 	input_device_ref *devices[2];
580 	devices[0] = &device->device_ref;
581 	devices[1] = NULL;
582 
583 	fDevices.AddItem(device);
584 
585 	return RegisterDevices(devices);
586 }
587 
588 
589 status_t
590 KeyboardInputDevice::RemoveDevice(const char *path)
591 {
592 	CALLED();
593 	keyboard_device *device;
594 	for (int i = 0; (device = (keyboard_device *)fDevices.ItemAt(i)) != NULL; i++) {
595 		if (!strcmp(device->path, path)) {
596 			fDevices.RemoveItem(device);
597 
598 			input_device_ref *devices[2];
599 			devices[0] = &device->device_ref;
600 			devices[1] = NULL;
601 			UnregisterDevices(devices);
602 
603 			delete device;
604 			return B_OK;
605 		}
606 	}
607 
608 	return B_ENTRY_NOT_FOUND;
609 }
610 
611 
612 int32
613 KeyboardInputDevice::DeviceWatcher(void *arg)
614 {
615 	CALLED();
616 	keyboard_device *dev = (keyboard_device *)arg;
617 	uint8 buffer[16];
618 	uint8 activeDeadKey = 0;
619 	Keymap *keymap = &dev->owner->fKeymap;
620 	uint32 lastKeyCode = 0;
621 	uint32 repeatCount = 1;
622 	uint8 states[16];
623 
624 	memset(states, 0, sizeof(states));
625 
626 	LOG("%s\n", __PRETTY_FUNCTION__);
627 
628 	while (dev->active) {
629 		if (ioctl(dev->fd, KB_READ, &buffer) != B_OK)
630 			return 0;
631 
632 		uint32 keycode = 0;
633 		bool isKeyDown = false;
634 		bigtime_t timestamp = 0;
635 
636 		LOG("KB_READ :");
637 
638 		if (dev->isAT) {
639 			at_kbd_io *at_kbd = (at_kbd_io *)buffer;
640 			if (at_kbd->scancode > 0)
641 				keycode = kATKeycodeMap[at_kbd->scancode-1];
642 			isKeyDown = at_kbd->is_keydown;
643 			timestamp = at_kbd->timestamp;
644 			LOG(" %02x", at_kbd->scancode);
645 		} else {
646 			raw_key_info *raw_kbd = (raw_key_info *)buffer;
647 			isKeyDown = raw_kbd->is_keydown;
648 			timestamp = raw_kbd->timestamp;
649 			keycode = raw_kbd->be_keycode;
650 		}
651 
652 		if (keycode == 0)
653 			continue;
654 
655 		LOG(" %Ld, %02x, %02lx\n", timestamp, isKeyDown, keycode);
656 
657 		if (isKeyDown && keycode == 0x68) {
658 			// MENU KEY for OpenTracker 5.2.0+
659 			bool noOtherKeyPressed = true;
660 			for (int32 i = 0; i < 16; i++) {
661 				if (states[i] != 0) {
662 					noOtherKeyPressed = false;
663 					break;
664 				}
665 			}
666 
667 			if (noOtherKeyPressed) {
668 				BMessenger deskbar("application/x-vnd.Be-TSKB");
669 				if (deskbar.IsValid())
670 					deskbar.SendMessage('BeMn');
671 			}
672 		}
673 
674 		if (keycode < 256) {
675 			if (isKeyDown)
676 				states[(keycode) >> 3] |= (1 << (7 - (keycode & 0x7)));
677 			else
678 				states[(keycode) >> 3] &= (!(1 << (7 - (keycode & 0x7))));
679 		}
680 
681 		if (isKeyDown
682 			&& keycode == 0x34 // DELETE KEY
683 			&& (states[0x5c >> 3] & (1 << (7 - (0x5c & 0x7))))
684 			&& (states[0x5d >> 3] & (1 << (7 - (0x5d & 0x7))))) {
685 			LOG("TeamMonitor called\n");
686 
687 			// show the team monitor
688 			if (dev->owner->fTMWindow == NULL)
689 				dev->owner->fTMWindow = new (std::nothrow) TMWindow();
690 
691 			if (dev->owner->fTMWindow != NULL) {
692 				dev->owner->fTMWindow->Enable();
693 
694 				// cancel timer only for R5
695 				if (ioctl(dev->fd, KB_CANCEL_CONTROL_ALT_DEL, NULL) == B_OK)
696 					LOG("KB_CANCEL_CONTROL_ALT_DEL : OK\n");
697 			}
698 		}
699 
700 		uint32 modifiers = keymap->Modifier(keycode);
701 		if (modifiers
702 			&& (!(modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))
703 				|| isKeyDown)) {
704 			BMessage *msg = new BMessage;
705 			if (msg == NULL)
706 				continue;
707 
708 			msg->AddInt64("when", timestamp);
709 			msg->what = B_MODIFIERS_CHANGED;
710 			msg->AddInt32("be:old_modifiers", dev->modifiers);
711 
712 			if ((isKeyDown && !(modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK)))
713 				|| (isKeyDown && !(dev->modifiers & modifiers)))
714 				dev->modifiers |= modifiers;
715 			else
716 				dev->modifiers &= ~modifiers;
717 
718 			msg->AddInt32("modifiers", dev->modifiers);
719 			msg->AddData("states", B_UINT8_TYPE, states, 16);
720 
721 			if (dev->owner->EnqueueMessage(msg)!=B_OK)
722 				delete msg;
723 
724 			if (modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))
725 				dev->owner->SetLeds(dev);
726 		}
727 
728 		uint8 newDeadKey = 0;
729 		if (activeDeadKey == 0)
730 			newDeadKey = keymap->IsDeadKey(keycode, dev->modifiers);
731 
732 		// new dead key behaviour
733 #if 0
734 		if (newDeadKey == 0) {
735 			keymap->GetChars(keycode, dev->modifiers, activeDeadKey, &str, &numBytes);
736 			keymap->GetChars(keycode, 0, 0, &str2, &numBytes2);
737 		}
738 #endif
739 
740 		// R5-like dead key behaviour
741 		if (newDeadKey == 0) {
742 			char *str = NULL, *str2 = NULL;
743 			int32 numBytes = 0, numBytes2 = 0;
744 			keymap->GetChars(keycode, dev->modifiers, activeDeadKey, &str, &numBytes);
745 			keymap->GetChars(keycode, 0, 0, &str2, &numBytes2);
746 
747 			BMessage *msg = new BMessage;
748 			if (msg == NULL)
749 				continue;
750 
751 			if (numBytes > 0)
752 				msg->what = isKeyDown ? B_KEY_DOWN : B_KEY_UP;
753 			else
754 				msg->what = isKeyDown ? B_UNMAPPED_KEY_DOWN : B_UNMAPPED_KEY_UP;
755 
756 			msg->AddInt64("when", timestamp);
757 			msg->AddInt32("key", keycode);
758 			msg->AddInt32("modifiers", dev->modifiers);
759 			msg->AddData("states", B_UINT8_TYPE, states, 16);
760 			if (numBytes > 0) {
761 				for (int i = 0; i < numBytes; i++) {
762 					msg->AddInt8("byte", (int8)str[i]);
763 				}
764 				msg->AddString("bytes", str);
765 
766 				if (numBytes2 <= 0) {
767 					numBytes2 = 1;
768 					delete[] str2;
769 					str2 = str;
770 				} else
771 					delete[] str;
772 
773 				if (isKeyDown && lastKeyCode == keycode) {
774 					repeatCount++;
775 					msg->AddInt32("be:key_repeat", repeatCount);
776 				} else
777 					repeatCount = 1;
778 			} else
779 				delete[] str;
780 
781 			if (numBytes2 > 0)
782 				msg->AddInt32("raw_char", (uint32)((uint8)str2[0] & 0x7f));
783 
784 			delete[] str2;
785 
786 			if (dev->owner->EnqueueMessage(msg) != B_OK)
787 				delete msg;
788 		}
789 
790 		if (!isKeyDown && !modifiers)
791 			activeDeadKey = newDeadKey;
792 
793 		lastKeyCode = keycode;
794 	}
795 
796 	return 0;
797 }
798 
799 
800 void
801 KeyboardInputDevice::RecursiveScan(const char *directory)
802 {
803 	CALLED();
804 	BEntry entry;
805 	BDirectory dir(directory);
806 	while (dir.GetNextEntry(&entry) == B_OK) {
807 		BPath path;
808 		entry.GetPath(&path);
809 		if (entry.IsDirectory())
810 			RecursiveScan(path.Path());
811 		else
812 			AddDevice(path.Path());
813 	}
814 }
815 
816 
817 void
818 KeyboardInputDevice::SetLeds(keyboard_device *device)
819 {
820 	if (device->fd < 0)
821 		return;
822 
823 	uint32 locks = device->modifiers;
824 	char lock_io[3];
825 	memset(lock_io, 0, sizeof(lock_io));
826 	if (locks & B_NUM_LOCK)
827 		lock_io[0] = 1;
828 	if (locks & B_CAPS_LOCK)
829 		lock_io[1] = 1;
830 	if (locks & B_SCROLL_LOCK)
831 		lock_io[2] = 1;
832 
833 	ioctl(device->fd, KB_SET_LEDS, &lock_io);
834 }
835 
836 
837 keyboard_device::keyboard_device(const char *path)
838 {
839 	// todo: initialize other members
840 	strcpy(this->path, path);
841 	device_ref.name = get_short_name(path);
842 	device_ref.type = B_KEYBOARD_DEVICE;
843 	device_ref.cookie = this;
844 }
845 
846 
847 keyboard_device::~keyboard_device()
848 {
849 	free(device_ref.name);
850 }
851 
852