xref: /haiku/src/add-ons/input_server/devices/keyboard/KeyboardInputDevice.cpp (revision 020cbad9d40235a2c50a81a42d69912a5ff8fbc4)
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 	status_t status = BInputServerDevice::InitCheck();
449 	if (status < B_OK)
450 		return status;
451 
452 	// TODO: this doesn't belong here!
453 	_RecursiveScan(kKeyboardDevicesDirectory);
454 
455 	StartMonitoringDevice(kKeyboardDevicesDirectoryPS2);
456 	StartMonitoringDevice(kKeyboardDevicesDirectoryUSB);
457 
458 	return B_OK;
459 }
460 
461 
462 status_t
463 KeyboardInputDevice::Start(const char *name, void *cookie)
464 {
465 	CALLED();
466 	keyboard_device *device = (keyboard_device *)cookie;
467 
468 	if ((device->fd = open(device->path, O_RDWR)) < B_OK) {
469 		fprintf(stderr, "error when opening %s: %s\n", device->path, strerror(errno));
470 		return B_ERROR;
471 	}
472 
473 	_InitFromSettings(device);
474 
475 	char threadName[B_OS_NAME_LENGTH];
476 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", name);
477 
478 	device->active = true;
479 	device->device_watcher = spawn_thread(_DeviceWatcher, threadName,
480 		kKeyboardThreadPriority, device);
481 	if (device->device_watcher < B_OK)
482 		return device->device_watcher;
483 
484 	resume_thread(device->device_watcher);
485 	return B_OK;
486 }
487 
488 
489 status_t
490 KeyboardInputDevice::Stop(const char *name, void *cookie)
491 {
492 	CALLED();
493 	keyboard_device *device = (keyboard_device *)cookie;
494 
495 	LOG("Stop(%s)\n", name);
496 
497 	close(device->fd);
498 	device->fd = -1;
499 
500 	device->active = false;
501 	if (device->device_watcher >= 0) {
502 		suspend_thread(device->device_watcher);
503 		resume_thread(device->device_watcher);
504 		status_t dummy;
505 		wait_for_thread(device->device_watcher, &dummy);
506 	}
507 
508 	if (fTMWindow) {
509 		fTMWindow->PostMessage(B_QUIT_REQUESTED);
510 		fTMWindow = NULL;
511 	}
512 
513 	return B_OK;
514 }
515 
516 
517 status_t
518 KeyboardInputDevice::Control(const char *name, void *cookie,
519 	uint32 command, BMessage *message)
520 {
521 	CALLED();
522 	LOG("Control(%s, code: %lu)\n", name, command);
523 
524 	if (command == B_NODE_MONITOR)
525 		_HandleMonitor(message);
526 	else if (command >= B_KEY_MAP_CHANGED
527 		&& command <= B_KEY_REPEAT_RATE_CHANGED) {
528 		_InitFromSettings(cookie, command);
529 	}
530 	return B_OK;
531 }
532 
533 
534 status_t
535 KeyboardInputDevice::_HandleMonitor(BMessage *message)
536 {
537 	CALLED();
538 	int32 opcode = 0;
539 	status_t status;
540 	if ((status = message->FindInt32("opcode", &opcode)) < B_OK)
541 		return status;
542 
543 	if (opcode != B_ENTRY_CREATED
544 		&& opcode != B_ENTRY_REMOVED)
545 		return B_OK;
546 
547 	BEntry entry;
548 	BPath path;
549 	dev_t device;
550 	ino_t directory;
551 	const char *name = NULL;
552 
553 	message->FindInt32("device", &device);
554 	message->FindInt64("directory", &directory);
555 	message->FindString("name", &name);
556 
557 	entry_ref ref(device, directory, name);
558 
559 	if ((status = entry.SetTo(&ref)) != B_OK)
560 		return status;
561 	if ((status = entry.GetPath(&path)) != B_OK)
562 		return status;
563 	if ((status = path.InitCheck()) != B_OK)
564 		return status;
565 
566 	if (opcode == B_ENTRY_CREATED)
567 		_AddDevice(path.Path());
568 	else
569 		_RemoveDevice(path.Path());
570 
571 	return status;
572 }
573 
574 
575 status_t
576 KeyboardInputDevice::_AddDevice(const char *path)
577 {
578 	CALLED();
579 	keyboard_device *device = new (std::nothrow) keyboard_device(path);
580 	if (device == NULL)
581 		return B_NO_MEMORY;
582 
583 	device->owner = this;
584 
585 	input_device_ref *devices[2];
586 	devices[0] = &device->device_ref;
587 	devices[1] = NULL;
588 
589 	fDevices.AddItem(device);
590 
591 	return RegisterDevices(devices);
592 }
593 
594 
595 status_t
596 KeyboardInputDevice::_RemoveDevice(const char *path)
597 {
598 	CALLED();
599 	keyboard_device *device;
600 	for (int i = 0; (device = (keyboard_device *)fDevices.ItemAt(i)) != NULL; i++) {
601 		if (!strcmp(device->path, path)) {
602 			fDevices.RemoveItem(device);
603 
604 			input_device_ref *devices[2];
605 			devices[0] = &device->device_ref;
606 			devices[1] = NULL;
607 			UnregisterDevices(devices);
608 
609 			delete device;
610 			return B_OK;
611 		}
612 	}
613 
614 	return B_ENTRY_NOT_FOUND;
615 }
616 
617 
618 /*static*/ int32
619 KeyboardInputDevice::_DeviceWatcher(void *arg)
620 {
621 	CALLED();
622 	keyboard_device* device = (keyboard_device *)arg;
623 	KeyboardInputDevice* owner = device->owner;
624 	uint8 buffer[16];
625 	uint8 activeDeadKey = 0;
626 	Keymap* keymap = &owner->fKeymap;
627 	uint32 lastKeyCode = 0;
628 	uint32 repeatCount = 1;
629 	uint8 states[16];
630 
631 	memset(states, 0, sizeof(states));
632 
633 	LOG("%s\n", __PRETTY_FUNCTION__);
634 
635 	while (device->active) {
636 		if (ioctl(device->fd, KB_READ, &buffer) != B_OK)
637 			return 0;
638 
639 		uint32 keycode = 0;
640 		bool isKeyDown = false;
641 		bigtime_t timestamp = 0;
642 
643 		LOG("KB_READ :");
644 
645 		if (device->isAT) {
646 			at_kbd_io *at_kbd = (at_kbd_io *)buffer;
647 			if (at_kbd->scancode > 0)
648 				keycode = kATKeycodeMap[at_kbd->scancode-1];
649 			isKeyDown = at_kbd->is_keydown;
650 			timestamp = at_kbd->timestamp;
651 			LOG(" %02x", at_kbd->scancode);
652 		} else {
653 			raw_key_info *raw_kbd = (raw_key_info *)buffer;
654 			isKeyDown = raw_kbd->is_keydown;
655 			timestamp = raw_kbd->timestamp;
656 			keycode = raw_kbd->be_keycode;
657 		}
658 
659 		if (keycode == 0)
660 			continue;
661 
662 		LOG(" %Ld, %02x, %02lx\n", timestamp, isKeyDown, keycode);
663 
664 		if (isKeyDown && keycode == 0x68) {
665 			// MENU KEY for OpenTracker 5.2.0+
666 			bool noOtherKeyPressed = true;
667 			for (int32 i = 0; i < 16; i++) {
668 				if (states[i] != 0) {
669 					noOtherKeyPressed = false;
670 					break;
671 				}
672 			}
673 
674 			if (noOtherKeyPressed) {
675 				BMessenger deskbar("application/x-vnd.Be-TSKB");
676 				if (deskbar.IsValid())
677 					deskbar.SendMessage('BeMn');
678 			}
679 		}
680 
681 		if (keycode < 256) {
682 			if (isKeyDown)
683 				states[(keycode) >> 3] |= (1 << (7 - (keycode & 0x7)));
684 			else
685 				states[(keycode) >> 3] &= (!(1 << (7 - (keycode & 0x7))));
686 		}
687 
688 		if (isKeyDown
689 			&& keycode == 0x34 // DELETE KEY
690 			&& (states[0x5c >> 3] & (1 << (7 - (0x5c & 0x7))))
691 			&& (states[0x5d >> 3] & (1 << (7 - (0x5d & 0x7))))) {
692 			LOG("TeamMonitor called\n");
693 
694 			// show the team monitor
695 			if (owner->fTMWindow == NULL)
696 				owner->fTMWindow = new (std::nothrow) TMWindow();
697 
698 			if (owner->fTMWindow != NULL) {
699 				owner->fTMWindow->Enable();
700 
701 				// cancel timer only for R5
702 				if (ioctl(device->fd, KB_CANCEL_CONTROL_ALT_DEL, NULL) == B_OK)
703 					LOG("KB_CANCEL_CONTROL_ALT_DEL : OK\n");
704 			}
705 		}
706 
707 		BAutolock lock(owner->fKeymapLock);
708 
709 		uint32 modifiers = keymap->Modifier(keycode);
710 		if (modifiers
711 			&& (!(modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))
712 				|| isKeyDown)) {
713 			BMessage *msg = new BMessage;
714 			if (msg == NULL)
715 				continue;
716 
717 			msg->AddInt64("when", timestamp);
718 			msg->what = B_MODIFIERS_CHANGED;
719 			msg->AddInt32("be:old_modifiers", device->modifiers);
720 
721 			if ((isKeyDown && !(modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK)))
722 				|| (isKeyDown && !(device->modifiers & modifiers)))
723 				device->modifiers |= modifiers;
724 			else
725 				device->modifiers &= ~modifiers;
726 
727 			msg->AddInt32("modifiers", device->modifiers);
728 			msg->AddData("states", B_UINT8_TYPE, states, 16);
729 
730 			if (owner->EnqueueMessage(msg)!=B_OK)
731 				delete msg;
732 
733 			if (modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))
734 				owner->_SetLeds(device);
735 		}
736 
737 		uint8 newDeadKey = 0;
738 		if (activeDeadKey == 0)
739 			newDeadKey = keymap->IsDeadKey(keycode, device->modifiers);
740 
741 		if (newDeadKey == 0) {
742 			char *string = NULL, *rawString = NULL;
743 			int32 numBytes = 0, rawNumBytes = 0;
744 			keymap->GetChars(keycode, device->modifiers, activeDeadKey, &string, &numBytes);
745 			keymap->GetChars(keycode, 0, 0, &rawString, &rawNumBytes);
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", device->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)string[i]);
763 				}
764 				msg->AddString("bytes", string);
765 
766 				if (rawNumBytes <= 0) {
767 					rawNumBytes = 1;
768 					delete[] rawString;
769 					rawString = string;
770 				} else
771 					delete[] string;
772 
773 				if (isKeyDown && lastKeyCode == keycode) {
774 					repeatCount++;
775 					msg->AddInt32("be:key_repeat", repeatCount);
776 				} else
777 					repeatCount = 1;
778 			} else
779 				delete[] string;
780 
781 			if (rawNumBytes > 0)
782 				msg->AddInt32("raw_char", (uint32)((uint8)rawString[0] & 0x7f));
783 
784 			delete[] rawString;
785 
786 			if (isKeyDown && !modifiers && activeDeadKey != 0
787 				&& device->input_method_started) {
788 				// a dead key was completed
789 				device->EnqueueInlineInputMethod(B_INPUT_METHOD_CHANGED,
790 					string, true, msg);
791 			} else if (owner->EnqueueMessage(msg) != B_OK)
792 				delete msg;
793 		} else if (isKeyDown) {
794 			// start of a dead key
795 			if (device->EnqueueInlineInputMethod(B_INPUT_METHOD_STARTED) == B_OK) {
796 				char *string = NULL;
797 				int32 numBytes = 0;
798 				keymap->GetChars(keycode, device->modifiers, 0, &string, &numBytes);
799 
800 				if (device->EnqueueInlineInputMethod(B_INPUT_METHOD_CHANGED, string) == B_OK)
801 					device->input_method_started = true;
802 			}
803 		}
804 
805 		if (!isKeyDown && !modifiers) {
806 			if (activeDeadKey != 0) {
807 				device->EnqueueInlineInputMethod(B_INPUT_METHOD_STOPPED);
808 				device->input_method_started = false;
809 			}
810 
811 			activeDeadKey = newDeadKey;
812 		}
813 
814 		lastKeyCode = isKeyDown ? keycode : 0;
815 	}
816 
817 	return 0;
818 }
819 
820 
821 void
822 KeyboardInputDevice::_RecursiveScan(const char *directory)
823 {
824 	CALLED();
825 	BEntry entry;
826 	BDirectory dir(directory);
827 	while (dir.GetNextEntry(&entry) == B_OK) {
828 		BPath path;
829 		entry.GetPath(&path);
830 		if (entry.IsDirectory())
831 			_RecursiveScan(path.Path());
832 		else
833 			_AddDevice(path.Path());
834 	}
835 }
836 
837 
838 void
839 KeyboardInputDevice::_SetLeds(keyboard_device *device)
840 {
841 	if (device->fd < 0)
842 		return;
843 
844 	uint32 locks = device->modifiers;
845 	char lock_io[3];
846 	memset(lock_io, 0, sizeof(lock_io));
847 	if (locks & B_NUM_LOCK)
848 		lock_io[0] = 1;
849 	if (locks & B_CAPS_LOCK)
850 		lock_io[1] = 1;
851 	if (locks & B_SCROLL_LOCK)
852 		lock_io[2] = 1;
853 
854 	ioctl(device->fd, KB_SET_LEDS, &lock_io);
855 }
856 
857 
858 //	#pragma mark -
859 
860 
861 keyboard_device::keyboard_device(const char *path)
862 	: BHandler("keyboard device"),
863 	owner(NULL),
864 	fd(-1),
865 	device_watcher(-1),
866 	active(false),
867 	input_method_started(false)
868 {
869 	strcpy(this->path, path);
870 	device_ref.name = get_short_name(path);
871 	device_ref.type = B_KEYBOARD_DEVICE;
872 	device_ref.cookie = this;
873 
874 	isAT = strstr(path, "keyboard/at") != NULL;
875 
876 	if (be_app->Lock()) {
877 		be_app->AddHandler(this);
878 		be_app->Unlock();
879 	}
880 }
881 
882 
883 keyboard_device::~keyboard_device()
884 {
885 	free(device_ref.name);
886 
887 	if (be_app->Lock()) {
888 		be_app->RemoveHandler(this);
889 		be_app->Unlock();
890 	}
891 }
892 
893 
894 status_t
895 keyboard_device::EnqueueInlineInputMethod(int32 opcode,
896 	const char* string, bool confirmed, BMessage* keyDown)
897 {
898 	BMessage* message = new BMessage(B_INPUT_METHOD_EVENT);
899 	if (message == NULL)
900 		return B_NO_MEMORY;
901 
902 	message->AddInt32("be:opcode", opcode);
903 	message->AddBool("be:inline_only", true);
904 
905 	if (string != NULL)
906 		message->AddString("be:string", string);
907 	if (confirmed)
908 		message->AddBool("be:confirmed", true);
909 	if (keyDown)
910 		message->AddMessage("be:translated", keyDown);
911 	if (opcode == B_INPUT_METHOD_STARTED)
912 		message->AddMessenger("be:reply_to", this);
913 
914 	status_t status = owner->EnqueueMessage(message);
915 	if (status != B_OK)
916 		delete message;
917 
918 	return status;
919 }
920 
921 
922 void
923 keyboard_device::MessageReceived(BMessage *message)
924 {
925 	if (message->what != B_INPUT_METHOD_EVENT) {
926 		BHandler::MessageReceived(message);
927 		return;
928 	}
929 
930 	int32 opcode;
931 	if (message->FindInt32("be:opcode", &opcode) != B_OK)
932 		return;
933 
934 	if (opcode == B_INPUT_METHOD_STOPPED)
935 		input_method_started = false;
936 }
937 
938