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