void handle_getstring (int key) { static int pos = 0; /* Cursor position */ static char buf[40]; if (KEY_ASCII(key) == 0) return; _D ("handling key: %02x", key); switch (key) { case KEY_ENTER: _D ("KEY_ENTER"); game.has_prompt = 0; buf[pos] = 0; strcpy (game.strings[stringdata.str], buf); _D (_D_WARN "buffer=[%s]", buf); buf[pos = 0] = 0; new_input_mode (INPUT_NORMAL); print_character (stringdata.x + strlen (game.strings[stringdata.str]) + 1, stringdata.y, ' ', game.color_fg, game.color_bg); return; case KEY_ESCAPE: _D ("KEY_ESCAPE"); game.has_prompt = 0; buf[pos = 0] = 0; strcpy (game.strings[stringdata.str], buf); new_input_mode (INPUT_NORMAL); /* new_input_mode (INPUT_MENU); */ break; case KEY_BACKSPACE: /*0x08:*/ if (!pos) break; print_character (stringdata.x + (pos + 1), stringdata.y, ' ', game.color_fg, game.color_bg); pos--; buf[pos] = 0; break; default: if (key < 0x20 || key > 0x7f) break; if (pos >= stringdata.len) break; buf[pos++] = key; buf[pos] = 0; /* Echo */ print_character (stringdata.x + pos, stringdata.y, buf[pos - 1], game.color_fg, game.color_bg); break; } /* print cursor */ print_character (stringdata.x + pos + 1, stringdata.y, (char)game.cursor_char, game.color_fg, game.color_bg); }
#define KEY_TYPE_ASCII 1 #define KEY_TYPE_SPECIAL 2 #define KEY_TYPE_MOUSE 3 #define KEY_ASCII(repeat,x) ((repeat << 31) | (KEY_TYPE_ASCII << 24) | (x)) #define KEY_SPECIAL(x) ((1 << 31) | (KEY_TYPE_SPECIAL << 24) | (x)) #define KEY_MOUSE(x) ((1 << 31) | (KEY_TYPE_MOUSE << 24) | (x)) #define KEY_TYPE(x) ((x >> 24) & 0x7) #define KEY_REPEAT(x) (x >> 31) /* XXX IMPROVE: might get packed tighter in 16bit words */ static const unsigned long keycode [] = { KEY_ASCII(0,'s'), /* PSP_CTRL_SELECT = 0x000001 */ 0, /* 0x000002 */ 0, /* 0x000004 */ KEY_ASCII(0,'a'), /* PSP_CTRL_START = 0x000008 */ KEY_SPECIAL(GLUT_KEY_UP), /* PSP_CTRL_UP = 0x000010 */ KEY_SPECIAL(GLUT_KEY_RIGHT), /* PSP_CTRL_RIGHT = 0x000020 */ KEY_SPECIAL(GLUT_KEY_DOWN), /* PSP_CTRL_DOWN = 0x000040 */ KEY_SPECIAL(GLUT_KEY_LEFT), /* PSP_CTRL_LEFT = 0x000080 */ KEY_MOUSE(GLUT_LEFT_BUTTON), /* PSP_CTRL_LTRIGGER = 0x000100 */ KEY_MOUSE(GLUT_RIGHT_BUTTON), /* PSP_CTRL_RTRIGGER = 0x000200 */ 0, /* 0x000400 */ 0, /* 0x000800 */ KEY_ASCII(1,'d'), /* PSP_CTRL_TRIANGLE = 0x001000 */ KEY_ASCII(1,'o'), /* PSP_CTRL_CIRCLE = 0x002000 */ KEY_ASCII(1,'x'), /* PSP_CTRL_CROSS = 0x004000 */ KEY_ASCII(1,'q'), /* PSP_CTRL_SQUARE = 0x008000 */
int handle_controller (int key) { struct vt_entry *v = &game.view_table[0]; int i; /* The Black Cauldron needs KEY_ESCAPE to use menus */ if (key == 0 /*|| key == KEY_ESCAPE*/) return FALSE; _D (_D_WARN "key = %04x", key); for (i = 0; i < MAX_DIRS; i++) { if (game.ev_keyp[i].data == key) { _D ("event %d: key press", i); game.ev_keyp[i].occured = TRUE; report ("event AC:%i occured\n", i); return TRUE; } } #ifdef USE_MOUSE if (key == BUTTON_LEFT) { if (getflag (F_menus_work) && mouse.y <= CHAR_LINES) { new_input_mode (INPUT_MENU); return TRUE; } } #endif if (game.player_control) { int d = 0; if (!KEY_ASCII (key)) { switch (key) { case KEY_UP: d = 1; break; case KEY_DOWN: d = 5; break; case KEY_LEFT: d = 7; break; case KEY_RIGHT: d = 3; break; case KEY_UP_RIGHT: d = 2; break; case KEY_DOWN_RIGHT: d = 4; break; case KEY_UP_LEFT: d = 8; break; case KEY_DOWN_LEFT: d = 6; break; } } #ifdef USE_MOUSE if (!opt.agimouse) { /* Handle mouse button events */ if (key == BUTTON_LEFT) { v->flags |= ADJ_EGO_XY; v->parm1 = WIN_TO_PIC_X(mouse.x); v->parm2 = WIN_TO_PIC_Y(mouse.y); return TRUE; } } #endif v->flags &= ~ADJ_EGO_XY; if (d || key == KEY_STATIONARY) { v->direction = v->direction == d ? 0 : d; return TRUE; } } return FALSE; }
/* If main_cycle returns false, don't process more events! */ int main_cycle() { unsigned int key, kascii; struct vt_entry *v = &game.view_table[0]; poll_timer(); /* msdos driver -> does nothing */ update_timer(); if (game.ver == 0) { _text->message_box("Warning: game CRC not listed, assuming AGI version 2.917."); game.ver = -1; } key = do_poll_keyboard(); /* In AGI Mouse emulation mode we must update the mouse-related * vars in every interpreter cycle. */ if (opt.agimouse) { game.vars[28] = mouse.x / 2; game.vars[29] = mouse.y; } if (key == KEY_PRIORITY) { _sprites->erase_both(); debug_.priority = !debug_.priority; show_pic(); _sprites->blit_both(); _sprites->commit_both(); key = 0; } if (key == KEY_STATUSLN) { debug_.statusline = !debug_.statusline; _text->write_status(); key = 0; } /* Click-to-walk mouse interface */ if (game.player_control && v->flags & ADJ_EGO_XY) { v->direction = get_direction(v->x_pos, v->y_pos, v->parm1, v->parm2, v->step_size); if (v->direction == 0) in_destination(v); } kascii = KEY_ASCII(key); if (kascii) setvar(V_key, kascii); process_key: switch (game.input_mode) { case INPUT_NORMAL: if (!handle_controller(key)) { if (key == 0 || !game.input_enabled) break; handle_keys(key); /* if ESC pressed, activate menu before * accept.input from the interpreter cycle * sets the input mode to normal again * (closes: #540856) */ if (key == KEY_ESCAPE) { key = 0; goto process_key; } /* commented out to close bug #438872 * if (key) game.keypress = key; */ } break; case INPUT_GETSTRING: handle_controller(key); handle_getstring(key); setvar(V_key, 0); /* clear ENTER key */ break; case INPUT_MENU: menu->keyhandler(key); do_update(); return false; case INPUT_NONE: handle_controller(key); if (key) game.keypress = key; break; } do_update(); if (game.msg_box_ticks > 0) game.msg_box_ticks--; return true; }
static void ledit_dispatch( UThread* ut, GWidget* wp, const GLViewEvent* ev ) { EX_PTR; //printf( "KR ledit %d\n", ev->type ); switch( ev->type ) { case GLV_EVENT_BUTTON_DOWN: if( (ev->code == GLV_BUTTON_LEFT) || (ev->code == GLV_BUTTON_MIDDLE) ) { ledit_setState( ut, ep, LEDIT_STATE_EDIT ); gui_setKeyFocus( wp ); if( ev->code == GLV_BUTTON_LEFT ) { // Don't have access to font here so just notify render. ep->newCursorX = ev->x; setFlag( NEW_CURSORX ); } else // if( ev->code == GLV_BUTTON_MIDDLE ) { ledit_paste( ut, ep ); setFlag( CHANGED ); } } break; case GLV_EVENT_BUTTON_UP: case GLV_EVENT_MOTION: break; case GLV_EVENT_KEY_DOWN: if( ep->strN ) { UBuffer* str = ur_buffer( ep->strN ); if( ev->state & GLV_MASK_CTRL ) { if( ev->code == KEY_k ) { // Remove from cursor to end (from Bash). int len = str->used - ep->editPos; if( len > 0 ) { ur_arrErase( str, ep->editPos, len ); setFlag( CHANGED ); } } else if( ev->code == KEY_v ) { ledit_paste( ut, ep ); setFlag( CHANGED ); } break; } switch( ev->code ) { case KEY_Return: goto activate; case KEY_Left: if( ep->editPos > 0 ) { --ep->editPos; setFlag( CHANGED ); } break; case KEY_Right: if( ep->editPos < str->used ) { ++ep->editPos; setFlag( CHANGED ); } break; case KEY_Home: ep->editPos = 0; setFlag( CHANGED ); break; case KEY_End: ep->editPos = str->used; setFlag( CHANGED ); break; case KEY_Insert: break; case KEY_Delete: if( ep->editPos < str->used ) { ur_arrErase( str, ep->editPos, 1 ); setFlag( CHANGED ); } break; case KEY_Back_Space: if( ep->editPos > 0 ) { --ep->editPos; ur_arrErase( str, ep->editPos, 1 ); setFlag( CHANGED ); } break; default: if( str->used < ep->maxChars ) { int key = KEY_ASCII(ev); if( key >= ' ' ) { if( ep->filterN ) { UBuffer* bin = ur_buffer( ep->filterN ); if( ! _bitIsSet( bin->ptr.b, key ) ) break; } ur_arrExpand( str, ep->editPos, 1 ); if( ur_strIsUcs2(str) ) str->ptr.u16[ ep->editPos ] = key; else str->ptr.b[ ep->editPos ] = key; ++ep->editPos; setFlag( CHANGED ); } else { gui_ignoreEvent( ev ); } } break; } } break; case GLV_EVENT_KEY_UP: gui_ignoreEvent( ev ); break; case GLV_EVENT_FOCUS_IN: break; case GLV_EVENT_FOCUS_OUT: ledit_setState( ut, ep, LEDIT_STATE_DISPLAY ); break; } return; activate: if( ep->codeN ) gui_doBlockN( ut, ep->codeN ); }
// If main_cycle returns false, don't process more events! int AgiEngine::mainCycle() { unsigned int key, kascii; VtEntry *v = &_game.viewTable[0]; pollTimer(); updateTimer(); key = doPollKeyboard(); // In AGI Mouse emulation mode we must update the mouse-related // vars in every interpreter cycle. // // We run AGIMOUSE always as a side effect if (getFeatures() & GF_AGIMOUSE || true) { _game.vars[28] = _mouse.x / 2; _game.vars[29] = _mouse.y; } if (key == KEY_PRIORITY) { _sprites->eraseBoth(); _debug.priority = !_debug.priority; _picture->showPic(); _sprites->blitBoth(); _sprites->commitBoth(); key = 0; } if (key == KEY_STATUSLN) { _debug.statusline = !_debug.statusline; writeStatus(); key = 0; } // Click-to-walk mouse interface if (_game.playerControl && v->flags & ADJ_EGO_XY) { int toX = v->parm1; int toY = v->parm2; // AGI Mouse games use ego's sprite's bottom left corner for mouse walking target. // Amiga games use ego's sprite's bottom center for mouse walking target. // TODO: Check what Atari ST AGI and Apple IIGS AGI use for mouse walking target. if (getPlatform() == Common::kPlatformAmiga) toX -= (v->xSize / 2); // Center ego's sprite horizontally // Adjust ego's sprite's mouse walking target position (These parameters are // controlled with the adj.ego.move.to.x.y-command). Note that these values rely // on the horizontal centering of the ego's sprite at least on the Amiga platform. toX += _game.adjMouseX; toY += _game.adjMouseY; v->direction = getDirection(v->xPos, v->yPos, toX, toY, v->stepSize); if (v->direction == 0) inDestination(v); } kascii = KEY_ASCII(key); if (kascii) setvar(vKey, kascii); process_key: switch (_game.inputMode) { case INPUT_NORMAL: if (!handleController(key)) { if (key == 0 || !_game.inputEnabled) break; handleKeys(key); // if ESC pressed, activate menu before // accept.input from the interpreter cycle // sets the input mode to normal again // (closes: #540856) if (key == KEY_ESCAPE) { key = 0; goto process_key; } // commented out to close Sarien bug #438872 //if (key) // _game.keypress = key; } break; case INPUT_GETSTRING: handleController(key); handleGetstring(key); setvar(vKey, 0); // clear ENTER key break; case INPUT_MENU: _menu->keyhandler(key); _gfx->doUpdate(); return false; case INPUT_NONE: handleController(key); if (key) _game.keypress = key; break; } _gfx->doUpdate(); if (_game.msgBoxTicks > 0) _game.msgBoxTicks--; return true; }
int AgiEngine::handleController(int key) { VtEntry *v = &_game.viewTable[0]; int i; // AGI 3.149 games, The Black Cauldron and King's Quest 4 need KEY_ESCAPE to use menus // Games with the GF_ESCPAUSE flag need KEY_ESCAPE to pause the game if (key == 0 || (key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) ) return false; if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == KEY_ENTER) && (_game.inputMode == INPUT_NONE)) { key = 0x20; // Set Enter key to Space in Manhunter when there's no text input } debugC(3, kDebugLevelInput, "key = %04x", key); for (i = 0; i < MAX_CONTROLLERS; i++) { if (_game.controllers[i].keycode == key) { debugC(3, kDebugLevelInput, "event %d: key press", _game.controllers[i].controller); _game.controllerOccured[_game.controllers[i].controller] = true; return true; } } if (key == BUTTON_LEFT) { if ((getflag(fMenusWork) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) { newInputMode(INPUT_MENU); return true; } } // Show predictive dialog if the user clicks on input area if (key == BUTTON_LEFT && (int)_mouse.y >= _game.lineUserInput * CHAR_LINES && (int)_mouse.y <= (_game.lineUserInput + 1) * CHAR_LINES) { GUI::PredictiveDialog _predictiveDialog; _predictiveDialog.runModal(); strcpy(_predictiveResult, _predictiveDialog.getResult()); if (strcmp(_predictiveResult, "")) { if (_game.inputMode == INPUT_NONE) { for (int n = 0; _predictiveResult[n]; n++) keyEnqueue(_predictiveResult[n]); } else { strcpy((char *)_game.inputBuffer, _predictiveResult); handleKeys(KEY_ENTER); } } /* if (predictiveDialog()) { if (_game.inputMode == INPUT_NONE) { for (int n = 0; _predictiveResult[n]; n++) keyEnqueue(_predictiveResult[n]); } else { strcpy((char *)_game.inputBuffer, _predictiveResult); handleKeys(KEY_ENTER); } } */ return true; } if (_game.playerControl) { int d = 0; if (!KEY_ASCII(key)) { switch (key) { case KEY_UP: d = 1; break; case KEY_DOWN: d = 5; break; case KEY_LEFT: d = 7; break; case KEY_RIGHT: d = 3; break; case KEY_UP_RIGHT: d = 2; break; case KEY_DOWN_RIGHT: d = 4; break; case KEY_UP_LEFT: d = 8; break; case KEY_DOWN_LEFT: d = 6; break; } } if (!(getFeatures() & GF_AGIMOUSE)) { // Handle mouse button events if (key == BUTTON_LEFT) { if (getGameID() == GID_PQ1 && _game.vars[vCurRoom] == 116) { // WORKAROUND: Special handling for mouse clicks in the newspaper // screen of PQ1. Fixes bug #3018770. d = 3; // fake a right arrow key (next page) } else { // Click-to-walk mouse interface v->flags |= fAdjEgoXY; v->parm1 = WIN_TO_PIC_X(_mouse.x); v->parm2 = WIN_TO_PIC_Y(_mouse.y); return true; } } } if (d || key == KEY_STATIONARY) { v->flags &= ~fAdjEgoXY; v->direction = v->direction == d ? 0 : d; return true; } } return false; }
void AgiEngine::handleGetstring(int key) { static int pos = 0; // Cursor position static char buf[40]; if (KEY_ASCII(key) == 0) return; debugC(3, kDebugLevelInput, "handling key: %02x", key); switch (key) { case BUTTON_LEFT: if ((int)_mouse.y >= _stringdata.y * CHAR_LINES && (int)_mouse.y <= (_stringdata.y + 1) * CHAR_LINES) { GUI::PredictiveDialog _predictiveDialog; _predictiveDialog.runModal(); strcpy(_predictiveResult, _predictiveDialog.getResult()); if (strcmp(_predictiveResult, "")) { strcpy(_game.strings[_stringdata.str], _predictiveResult); newInputMode(INPUT_NORMAL); _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1, _stringdata.y, ' ', _game.colorFg, _game.colorBg); return; } /* if (predictiveDialog()) { strcpy(_game.strings[_stringdata.str], _predictiveResult); newInputMode(INPUT_NORMAL); _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1, _stringdata.y, ' ', _game.colorFg, _game.colorBg); return; } */ } break; case KEY_ENTER: debugC(3, kDebugLevelInput, "KEY_ENTER"); _game.hasPrompt = 0; buf[pos] = 0; strcpy(_game.strings[_stringdata.str], buf); debugC(3, kDebugLevelInput, "buffer=[%s]", buf); buf[pos = 0] = 0; newInputMode(INPUT_NORMAL); _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1, _stringdata.y, ' ', _game.colorFg, _game.colorBg); return; case KEY_ESCAPE: debugC(3, kDebugLevelInput, "KEY_ESCAPE"); _game.hasPrompt = 0; buf[pos = 0] = 0; strcpy(_game.strings[_stringdata.str], buf); newInputMode(INPUT_NORMAL); // newInputMode(INPUT_MENU); break; case KEY_BACKSPACE: // 0x08 if (!pos) break; _gfx->printCharacter(_stringdata.x + (pos + 1), _stringdata.y, ' ', _game.colorFg, _game.colorBg); pos--; buf[pos] = 0; break; default: if (key < 0x20 || key > 0x7f) break; if (pos >= _stringdata.len) break; buf[pos++] = key; buf[pos] = 0; // Echo _gfx->printCharacter(_stringdata.x + pos, _stringdata.y, buf[pos - 1], _game.colorFg, _game.colorBg); break; } // print cursor _gfx->printCharacter(_stringdata.x + pos + 1, _stringdata.y, (char)_game.cursorChar, _game.colorFg, _game.colorBg); }