* Added an emergency key mechanism to the kernel, inspired by Jan Klötzke's
patch from about a year ago (I couldn't use any code of his yet, though, but there are a few things left). The emergency keys are triggered by pressing Alt-SysReq + key. * By default, only Alt-SysReq+'d' is used as a means to deliberately enter the kernel debugger. F12 belongs to userland again, now :-) * Debugger add-ons now have another optional method to implement their own emergency keys - 'd' for the debugger cannot be overridden, though. * The mechanism can be turned off via a new kernel setting, so it's not that easy anymore to "crash" Haiku if you don't want to. * Right now, the PS/2 driver, and the pre-input_server in-kernel debugger keyboard mini-driver support this, USB not yet. * Minor cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31660 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
8ef9253a59
commit
c755ecfe96
@ -50,5 +50,8 @@
|
||||
# (system shutdown, battery info, ...)
|
||||
# default is off
|
||||
|
||||
#emergency_keys false
|
||||
# Disables emergency keys (ie. Alt-SysReq+*), enabled by default
|
||||
|
||||
#acpi true
|
||||
# ACPI support, off by default
|
||||
|
@ -28,7 +28,11 @@
|
||||
#endif
|
||||
|
||||
#define ASSERT_ALWAYS(x) \
|
||||
do { if (!(x)) { panic("ASSERT FAILED (%s:%d): %s\n", __FILE__, __LINE__, #x); } } while (0)
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
panic("ASSERT FAILED (%s:%d): %s\n", __FILE__, __LINE__, #x); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_ALWAYS_PRINT(x, format...) \
|
||||
do { \
|
||||
@ -66,10 +70,13 @@ struct debugger_module_info {
|
||||
void (*enter_debugger)(void);
|
||||
void (*exit_debugger)(void);
|
||||
|
||||
// io hooks
|
||||
// I/O hooks
|
||||
int (*debugger_puts)(const char *str, int32 length);
|
||||
int (*debugger_getchar)(void);
|
||||
// TODO: add hooks for tunnelling gdb ?
|
||||
|
||||
// Misc. hooks
|
||||
bool (*emergency_key_pressed)(char key);
|
||||
};
|
||||
|
||||
struct debugger_demangle_module_info {
|
||||
@ -114,6 +121,7 @@ extern void debug_set_page_fault_info(addr_t faultAddress, addr_t pc,
|
||||
uint32 flags);
|
||||
extern debug_page_fault_info* debug_get_page_fault_info();
|
||||
extern void debug_trap_cpu_in_kdl(bool returnIfHandedOver);
|
||||
extern bool debug_emergency_key_pressed(char key);
|
||||
|
||||
extern char kgetc(void);
|
||||
extern void kputs(const char *string);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007 Haiku, Inc.
|
||||
* Copyright 2004-2009 Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors (in chronological order):
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
/*! PS/2 bus manager */
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ps2_common.h"
|
||||
@ -277,32 +278,33 @@ ps2_interrupt(void* cookie)
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
|
||||
if (atomic_get(&sIgnoreInterrupts)) {
|
||||
TRACE("ps2: ps2_interrupt ignoring, ctrl 0x%02x (%s)\n", ctrl, (ctrl & PS2_STATUS_AUX_DATA) ? "aux" : "keyb");
|
||||
TRACE("ps2: ps2_interrupt ignoring, ctrl 0x%02x (%s)\n", ctrl,
|
||||
(ctrl & PS2_STATUS_AUX_DATA) ? "aux" : "keyb");
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
data = ps2_read_data();
|
||||
|
||||
if (ctrl & PS2_STATUS_AUX_DATA) {
|
||||
if ((ctrl & PS2_STATUS_AUX_DATA) != 0) {
|
||||
uint8 idx;
|
||||
if (gActiveMultiplexingEnabled) {
|
||||
idx = ctrl >> 6;
|
||||
error = (ctrl & 0x04) != 0;
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (mouse %d)\n", ctrl, data, idx);
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (mouse %d)\n",
|
||||
ctrl, data, idx);
|
||||
} else {
|
||||
idx = 0;
|
||||
error = (ctrl & 0xC0) != 0;
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (aux)\n", ctrl, data);
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (aux)\n", ctrl,
|
||||
data);
|
||||
}
|
||||
dev = &ps2_device[PS2_DEVICE_MOUSE + idx];
|
||||
} else {
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (keyb)\n", ctrl, data);
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (keyb)\n", ctrl,
|
||||
data);
|
||||
|
||||
dev = &ps2_device[PS2_DEVICE_KEYB];
|
||||
error = (ctrl & 0xC0) != 0;
|
||||
|
||||
// TODO: remove me again; let us drop into the kernel debugger with F12
|
||||
if (data == 88)
|
||||
panic("keyboard requested halt.\n");
|
||||
}
|
||||
|
||||
dev->history[1] = dev->history[0];
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2004-2007 Haiku, Inc.
|
||||
* Copyright 2004-2009 Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors (in chronological order):
|
||||
@ -10,11 +10,16 @@
|
||||
|
||||
/*! PS/2 keyboard device driver */
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <debugger_keymaps.h>
|
||||
|
||||
#include "ps2_service.h"
|
||||
#include "kb_mouse_driver.h"
|
||||
#include "packet_buffer.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define KEY_BUFFER_SIZE 100
|
||||
// we will buffer 100 key strokes before we start dropping them
|
||||
@ -27,6 +32,10 @@ enum {
|
||||
|
||||
enum {
|
||||
EXTENDED_KEY = 0xe0,
|
||||
|
||||
LEFT_ALT_KEY = 0x38,
|
||||
RIGHT_ALT_KEY = 0xb8,
|
||||
SYS_REQ_KEY = 0x54
|
||||
};
|
||||
|
||||
|
||||
@ -38,6 +47,7 @@ static bool sIsExtended = false;
|
||||
static int32 sKeyboardRepeatRate;
|
||||
static bigtime_t sKeyboardRepeatDelay;
|
||||
|
||||
|
||||
static status_t
|
||||
set_leds(led_info *ledInfo)
|
||||
{
|
||||
@ -52,7 +62,8 @@ set_leds(led_info *ledInfo)
|
||||
if (ledInfo->caps_lock)
|
||||
leds |= LED_CAPS;
|
||||
|
||||
return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_KEYBOARD_SET_LEDS, &leds, 1, NULL, 0);
|
||||
return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB],
|
||||
PS2_CMD_KEYBOARD_SET_LEDS, &leds, 1, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -84,13 +95,20 @@ set_typematic(int32 rate, bigtime_t delay)
|
||||
else
|
||||
value |= 0 << 5;
|
||||
|
||||
return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_KEYBOARD_SET_TYPEMATIC, &value, 1, NULL, 0);
|
||||
return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB],
|
||||
PS2_CMD_KEYBOARD_SET_TYPEMATIC, &value, 1, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
keyboard_handle_int(ps2_dev *dev)
|
||||
{
|
||||
enum emergency_keys {
|
||||
EMERGENCY_LEFT_ALT = 0x01,
|
||||
EMERGENCY_RIGHT_ALT = 0x02,
|
||||
EMERGENCY_SYS_REQ = 0x04,
|
||||
};
|
||||
static int emergencyKeyStatus = 0;
|
||||
at_kbd_io keyInfo;
|
||||
uint8 scancode = dev->history[0].data;
|
||||
|
||||
@ -107,7 +125,7 @@ keyboard_handle_int(ps2_dev *dev)
|
||||
|
||||
// TRACE("scancode: %x\n", scancode);
|
||||
|
||||
if (scancode & 0x80) {
|
||||
if ((scancode & 0x80) != 0) {
|
||||
keyInfo.is_keydown = false;
|
||||
scancode &= 0x7f;
|
||||
} else
|
||||
@ -118,12 +136,33 @@ keyboard_handle_int(ps2_dev *dev)
|
||||
sIsExtended = false;
|
||||
}
|
||||
|
||||
// Handle emergency keys
|
||||
if (scancode == LEFT_ALT_KEY || scancode == RIGHT_ALT_KEY) {
|
||||
// left or right alt-key pressed
|
||||
if (keyInfo.is_keydown) {
|
||||
emergencyKeyStatus |= scancode == LEFT_ALT_KEY
|
||||
? EMERGENCY_LEFT_ALT : EMERGENCY_RIGHT_ALT;
|
||||
} else {
|
||||
emergencyKeyStatus &= ~(scancode == LEFT_ALT_KEY
|
||||
? EMERGENCY_LEFT_ALT : EMERGENCY_RIGHT_ALT);
|
||||
}
|
||||
} else if (scancode == SYS_REQ_KEY) {
|
||||
if (keyInfo.is_keydown)
|
||||
emergencyKeyStatus |= EMERGENCY_SYS_REQ;
|
||||
else
|
||||
emergencyKeyStatus &= EMERGENCY_SYS_REQ;
|
||||
} else if (emergencyKeyStatus > EMERGENCY_SYS_REQ
|
||||
&& debug_emergency_key_pressed(kUnshiftedKeymap[scancode]))
|
||||
return B_HANDLED_INTERRUPT;
|
||||
|
||||
keyInfo.timestamp = dev->history[0].time;
|
||||
keyInfo.scancode = scancode;
|
||||
|
||||
if (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo, sizeof(keyInfo)) == 0) {
|
||||
// If there is no space left in the buffer, we drop this key stroke. We avoid
|
||||
// dropping old key strokes, to not destroy what already was typed.
|
||||
if (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo,
|
||||
sizeof(keyInfo)) == 0) {
|
||||
// If there is no space left in the buffer, we drop this key stroke. We
|
||||
// avoid dropping old key strokes, to not destroy what already was
|
||||
// typed.
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
@ -150,11 +189,14 @@ read_keyboard_packet(at_kbd_io *packet)
|
||||
}
|
||||
|
||||
if (packet_buffer_read(sKeyBuffer, (uint8 *)packet, sizeof(*packet)) == 0) {
|
||||
TRACE("ps2: read_keyboard_packet, Error reading packet: %s\n", strerror(status));
|
||||
TRACE("ps2: read_keyboard_packet, Error reading packet: %s\n",
|
||||
strerror(status));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("ps2: read_keyboard_packet: scancode: %x, keydown: %s\n", packet->scancode, packet->is_keydown ? "true" : "false");
|
||||
TRACE("ps2: read_keyboard_packet: scancode: %x, keydown: %s\n",
|
||||
packet->scancode, packet->is_keydown ? "true" : "false");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -184,13 +226,16 @@ probe_keyboard(void)
|
||||
// return B_ERROR;
|
||||
// }
|
||||
|
||||
status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL, 0, &data, 1);
|
||||
status = ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], PS2_CMD_RESET, NULL,
|
||||
0, &data, 1);
|
||||
if (status != B_OK || data != 0xaa) {
|
||||
INFO("ps2: keyboard reset failed, status 0x%08lx, data 0x%02x\n", status, data);
|
||||
INFO("ps2: keyboard reset failed, status 0x%08lx, data 0x%02x\n",
|
||||
status, data);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// default settings after keyboard reset: delay = 0x01 (500 ms), rate = 0x0b (10.9 chr/sec)
|
||||
// default settings after keyboard reset: delay = 0x01 (500 ms),
|
||||
// rate = 0x0b (10.9 chr/sec)
|
||||
sKeyboardRepeatRate = ((31 - 0x0b) * 280) / 31 + 20;
|
||||
sKeyboardRepeatDelay = 500000;
|
||||
|
||||
@ -328,24 +373,29 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
||||
case KB_SET_KEY_REPEATING:
|
||||
{
|
||||
TRACE("ps2: ioctl KB_SET_KEY_REPEATING\n");
|
||||
// 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds with "ack" (0xFA).
|
||||
return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0, NULL, 0);
|
||||
// 0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds
|
||||
// with "ack" (0xFA).
|
||||
return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xfa, NULL, 0,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
case KB_SET_KEY_NONREPEATING:
|
||||
{
|
||||
TRACE("ps2: ioctl KB_SET_KEY_NONREPEATING\n");
|
||||
// 0xF8 (Set All Keys Make/Break) - Keyboard responds with "ack" (0xFA).
|
||||
return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xf8, NULL, 0, NULL, 0);
|
||||
// 0xF8 (Set All Keys Make/Break) - Keyboard responds with "ack"
|
||||
// (0xFA).
|
||||
return ps2_dev_command(&ps2_device[PS2_DEVICE_KEYB], 0xf8, NULL, 0,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
case KB_SET_KEY_REPEAT_RATE:
|
||||
{
|
||||
int32 key_repeat_rate;
|
||||
TRACE("ps2: ioctl KB_SET_KEY_REPEAT_RATE\n");
|
||||
if (user_memcpy(&key_repeat_rate, buffer, sizeof(key_repeat_rate)) < B_OK)
|
||||
if (user_memcpy(&key_repeat_rate, buffer, sizeof(key_repeat_rate))
|
||||
!= B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
if (set_typematic(key_repeat_rate, sKeyboardRepeatDelay) < B_OK)
|
||||
if (set_typematic(key_repeat_rate, sKeyboardRepeatDelay) != B_OK)
|
||||
return B_ERROR;
|
||||
sKeyboardRepeatRate = key_repeat_rate;
|
||||
return B_OK;
|
||||
@ -354,16 +404,18 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
||||
case KB_GET_KEY_REPEAT_RATE:
|
||||
{
|
||||
TRACE("ps2: ioctl KB_GET_KEY_REPEAT_RATE\n");
|
||||
return user_memcpy(buffer, &sKeyboardRepeatRate, sizeof(sKeyboardRepeatRate));
|
||||
return user_memcpy(buffer, &sKeyboardRepeatRate,
|
||||
sizeof(sKeyboardRepeatRate));
|
||||
}
|
||||
|
||||
case KB_SET_KEY_REPEAT_DELAY:
|
||||
{
|
||||
bigtime_t key_repeat_delay;
|
||||
TRACE("ps2: ioctl KB_SET_KEY_REPEAT_DELAY\n");
|
||||
if (user_memcpy(&key_repeat_delay, buffer, sizeof(key_repeat_delay)) < B_OK)
|
||||
if (user_memcpy(&key_repeat_delay, buffer, sizeof(key_repeat_delay))
|
||||
!= B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
if (set_typematic(sKeyboardRepeatRate, key_repeat_delay) < B_OK)
|
||||
if (set_typematic(sKeyboardRepeatRate, key_repeat_delay) != B_OK)
|
||||
return B_ERROR;
|
||||
sKeyboardRepeatDelay = key_repeat_delay;
|
||||
return B_OK;
|
||||
@ -373,7 +425,8 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
||||
case KB_GET_KEY_REPEAT_DELAY:
|
||||
{
|
||||
TRACE("ps2: ioctl KB_GET_KEY_REPEAT_DELAY\n");
|
||||
return user_memcpy(buffer, &sKeyboardRepeatDelay, sizeof(sKeyboardRepeatDelay));
|
||||
return user_memcpy(buffer, &sKeyboardRepeatDelay,
|
||||
sizeof(sKeyboardRepeatDelay));
|
||||
}
|
||||
|
||||
case KB_GET_KEYBOARD_ID:
|
||||
@ -389,6 +442,7 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
device_hooks gKeyboardDeviceHooks = {
|
||||
keyboard_open,
|
||||
keyboard_close,
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de
|
||||
* Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de
|
||||
* Copyright 2001, Rob Judd <judd@ob-wan.com>
|
||||
* Copyright 2002, Marcus Overhagen <marcus@overhagen.de>
|
||||
* Distributed under the terms of the Haiku License.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
@ -52,6 +52,7 @@ enum keycodes {
|
||||
LEFT_CONTROL = 29,
|
||||
|
||||
LEFT_ALT = 56,
|
||||
RIGHT_ALT = 58,
|
||||
|
||||
CURSOR_LEFT = 75,
|
||||
CURSOR_RIGHT = 77,
|
||||
@ -62,8 +63,8 @@ enum keycodes {
|
||||
PAGE_UP = 73,
|
||||
PAGE_DOWN = 81,
|
||||
|
||||
BREAK = 198, // TODO: >= 128 can't be valid
|
||||
DELETE = 83,
|
||||
SYS_REQ = 84,
|
||||
F12 = 88,
|
||||
};
|
||||
|
||||
@ -108,7 +109,8 @@ static int32
|
||||
debug_keyboard_interrupt(void *data)
|
||||
{
|
||||
static bool controlPressed = false;
|
||||
static bool altPressed;
|
||||
static bool altPressed = false;
|
||||
static bool sysReqPressed = false;
|
||||
uint8 key;
|
||||
|
||||
key = in8(PS2_PORT_DATA);
|
||||
@ -117,8 +119,10 @@ debug_keyboard_interrupt(void *data)
|
||||
if (key & 0x80) {
|
||||
if (key == LEFT_CONTROL)
|
||||
controlPressed = false;
|
||||
if (key == LEFT_ALT)
|
||||
else if (key == LEFT_ALT)
|
||||
altPressed = false;
|
||||
else if (key == SYS_REQ)
|
||||
sysReqPressed = false;
|
||||
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
@ -129,22 +133,22 @@ debug_keyboard_interrupt(void *data)
|
||||
break;
|
||||
|
||||
case LEFT_ALT:
|
||||
case RIGHT_ALT:
|
||||
altPressed = true;
|
||||
break;
|
||||
|
||||
case SYS_REQ:
|
||||
sysReqPressed = true;
|
||||
break;
|
||||
|
||||
case DELETE:
|
||||
if (controlPressed && altPressed)
|
||||
arch_cpu_shutdown(true);
|
||||
break;
|
||||
|
||||
/* the following code has two possibilities because of issues
|
||||
* with BeBochs & BeOS (all special keys don't map to anything
|
||||
* useful, and SYS_REQ does a screen dump in BeOS).
|
||||
* ToDo: remove these key functions some day...
|
||||
*/
|
||||
case F12:
|
||||
case BREAK:
|
||||
panic("Keyboard Requested Halt\n");
|
||||
default:
|
||||
if (altPressed && sysReqPressed)
|
||||
debug_emergency_key_pressed(kUnshiftedKeymap[key]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
@ -63,6 +63,7 @@ static bool sBlueScreenEnabled = false;
|
||||
// must always be false on startup
|
||||
static bool sDebugScreenEnabled = false;
|
||||
static bool sBlueScreenOutput = true;
|
||||
static bool sEmergencyKeysEnabled = true;
|
||||
static spinlock sSpinlock = B_SPINLOCK_INITIALIZER;
|
||||
static int32 sDebuggerOnCPU = -1;
|
||||
|
||||
@ -1239,6 +1240,8 @@ debug_init_post_vm(kernel_args* args)
|
||||
"syslog_debug_output", sSyslogOutputEnabled, sSyslogOutputEnabled);
|
||||
sBlueScreenOutput = get_driver_boolean_parameter(handle,
|
||||
"bluescreen", true, true);
|
||||
sEmergencyKeysEnabled = get_driver_boolean_parameter(handle,
|
||||
"emergency_keys", sEmergencyKeysEnabled, sEmergencyKeysEnabled);
|
||||
|
||||
unload_driver_settings(handle);
|
||||
}
|
||||
@ -1350,6 +1353,30 @@ debug_trap_cpu_in_kdl(bool returnIfHandedOver)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
debug_emergency_key_pressed(char key)
|
||||
{
|
||||
if (!sEmergencyKeysEnabled)
|
||||
return false;
|
||||
|
||||
if (key == 'd') {
|
||||
kernel_debugger("Keyboard Requested Halt.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Broadcast to the kernel debugger modules
|
||||
|
||||
for (uint32 i = 0; i < kMaxDebuggerModules; i++) {
|
||||
if (sDebuggerModules[i] && sDebuggerModules[i]->emergency_key_pressed) {
|
||||
if (sDebuggerModules[i]->emergency_key_pressed(key))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - public API
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user