mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-09-22 22:48:08 +03:00
With the blocking modal_run(), the game's main loop is frozen while a menu is open, so the flag's input-suppression and VM-pause checks are unreachable. Quit requested during a modal is now handled by closing the modal and letting it propagate through the main loop.
481 lines
12 KiB
C
481 lines
12 KiB
C
/*
|
|
* sprite_event.c: SACT内の mouse/key イベントのハンドラ
|
|
*
|
|
* Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
|
|
* 1998- <masaki-c@is.aist-nara.ac.jp>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
/* $Id: sprite_event.c,v 1.5 2003/11/09 15:06:13 chikama Exp $ */
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#ifdef __EMSCRIPTEN__
|
|
#include <emscripten.h>
|
|
#endif
|
|
|
|
#include "portab.h"
|
|
#include "system.h"
|
|
#include "menu.h"
|
|
#include "input.h"
|
|
#include "nact.h"
|
|
#include "sact.h"
|
|
#include "sprite.h"
|
|
#include "sactsound.h"
|
|
#include "sactlog.h"
|
|
|
|
/*
|
|
SACT内のSpriteKey待ちやメッセージKey待ちなどを実現するため、X|SDL から
|
|
Key/Mouse イベントがあったときに、nact->ags.eventcb()によって他のモジュール
|
|
にイベントを送出できるようにした。
|
|
|
|
SACTでは最初に spev_callback でイベントを受け取るようにし、現在のキー待ちの
|
|
状態(sact.waittype)によってそれぞれのイベントハンドラを呼び出している。
|
|
|
|
現在のところ、1) メッセージキー待ち、2) 単純キー待ち、3) メニューキー待ち、
|
|
4) スプライトキー 5) バックログキー待ちの5つがある。
|
|
|
|
1)メッセージキー待ち
|
|
何かキーが押されるまで待つ。Zキースプライトの消去ができる。
|
|
|
|
2)単純キー待ち
|
|
1)と同じ
|
|
|
|
3)メニューキー待ち
|
|
メニューオープン時の処理。マウスが動いた時と、キー(orボタン)が離れたときに
|
|
いくつかの処理を行う。
|
|
|
|
4)スプライト待ち
|
|
SW/GETA/GETB/PUT/SWPUTスプライトの各処理を行う。
|
|
スプライトは番号の小さいものから順に上に重ねて表示し、下になっている
|
|
スプライトにイベントが伝わらないようにする
|
|
-> SpriteKey待ちの直前にスプライトの番号による depth map を作成し、
|
|
マウスの位置にあるスプライトの番号をで取り出す。
|
|
AlphaマスクつきのSpriteの場合、それを反映し、表示している場所のみに
|
|
depthmapを反映。
|
|
|
|
drag中のスプライトは常に最上位にくるように表示し、マウス移動等のイベント
|
|
は最初に処理する。
|
|
|
|
5)バックログ表示中のキー待ち
|
|
オリジナルと同じキー操作のはず
|
|
*/
|
|
|
|
|
|
static void cb_focused_swsp(void* s, void* data);
|
|
static void cb_defocused_swsp(void* s, void* data);
|
|
static int cb_focused(sprite_t *sp);
|
|
static int cb_defocused(sprite_t *sp);
|
|
static void cb_waitkey_simple(agsevent_t *e);
|
|
static void cb_waitkey_selection(agsevent_t *e);
|
|
|
|
/*
|
|
フォーカスを得たスプライトに説明スプライトが登録されていた場合の
|
|
説明スプライトの表示ON
|
|
*/
|
|
static void cb_focused_swsp(void* s, void* data) {
|
|
sprite_t *sp = (sprite_t *)s;
|
|
int *update = (int *)data;
|
|
bool oldstate = sp->show;
|
|
|
|
SACT_DEBUG("show up spex %d", sp->no);
|
|
|
|
sp->show = true;
|
|
if (oldstate != sp->show) {
|
|
(*update)++;
|
|
sp_updateme(sp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
フォーカスを得たスプライトに説明スプライトが登録されていた場合の
|
|
説明スプライトの表示OFF
|
|
*/
|
|
static void cb_defocused_swsp(void* s, void* data) {
|
|
sprite_t *sp = (sprite_t *)s;
|
|
int *update = (int *)data;
|
|
bool oldstate = sp->show;
|
|
|
|
SACT_DEBUG("hide spex %d", sp->no);
|
|
|
|
sp->show = false;
|
|
if (oldstate != sp->show) {
|
|
(*update)++;
|
|
sp_updateme(sp);
|
|
}
|
|
}
|
|
|
|
// zkey hide off
|
|
static void cb_focused_zkey(void* s, void* data) {
|
|
sprite_t *sp = (sprite_t *)s;
|
|
int *update = (int *)data;
|
|
bool oldstate = sp->show;
|
|
|
|
sp->show = sp->show_save;
|
|
if (oldstate != sp->show) {
|
|
(*update)++;
|
|
sp_updateme(sp);
|
|
}
|
|
}
|
|
|
|
// zkey hide on
|
|
static void cb_defocused_zkey(void* s, void* data) {
|
|
sprite_t *sp = (sprite_t *)s;
|
|
int *update = (int *)data;
|
|
bool oldstate = sp->show;
|
|
|
|
sp->show = false;
|
|
if (oldstate != sp->show) {
|
|
(*update)++;
|
|
sp_updateme(sp);
|
|
sp->show_save = oldstate;
|
|
}
|
|
}
|
|
|
|
/*
|
|
フォーカスを得たスプライトの処理
|
|
cg2があればcurcgをcg2に設定
|
|
|
|
drag中のスプライトがある場合
|
|
-> PUT/SWPUTスプライトのみ反応
|
|
drag中のスプライトがない場合
|
|
-> GETA/GETB/SWPUTスプライトのみ反応
|
|
*/
|
|
static int cb_focused(sprite_t *sp) {
|
|
int update = 0;
|
|
|
|
if (sact.draggedsp) {
|
|
if (sp->type != SPRITE_PUT &&
|
|
sp->type != SPRITE_SWPUT) return 0;
|
|
} else {
|
|
if (sp->type == SPRITE_PUT) return 0;
|
|
}
|
|
|
|
if (!sp->focused) {
|
|
if (sp->cg2) {
|
|
if (sp->curcg != sp->cg2) {
|
|
sp_updateme(sp);
|
|
}
|
|
sp->curcg = sp->cg2;
|
|
update++;
|
|
}
|
|
sp->focused = true;
|
|
SACT_DEBUG("get forcused %d, type %d", sp->no, sp->type);
|
|
if (sp->numsound1) {
|
|
ssnd_play(sp->numsound1);
|
|
}
|
|
}
|
|
|
|
return update;
|
|
}
|
|
|
|
/*
|
|
フォーカスを失ったスプライトの処理
|
|
curcg を cg1 にセット
|
|
*/
|
|
static int cb_defocused(sprite_t *sp) {
|
|
int update = 0;
|
|
|
|
if (sp->focused) {
|
|
if (sp->curcg != sp->cg1) {
|
|
sp_updateme(sp);
|
|
}
|
|
sp->curcg = sp->cg1;
|
|
update++;
|
|
sp->focused = false;
|
|
SACT_DEBUG("lost forcused %d", sp->no);
|
|
}
|
|
|
|
return update;
|
|
}
|
|
|
|
/*
|
|
WaitKeySimpleのcallback
|
|
*/
|
|
static void cb_waitkey_simple(agsevent_t *e) {
|
|
int cur, update = 0;
|
|
|
|
switch (e->type) {
|
|
case AGSEVENT_KEY_PRESS:
|
|
if (e->code == KEY_Z) {
|
|
cur = sys_get_ticks();
|
|
if (!sact.zhiding) {
|
|
slist_foreach(sact.sp_zhide, cb_defocused_zkey, &update);
|
|
sact.zhiding = true;
|
|
sact.zdooff = true;
|
|
sact.zofftime = cur;
|
|
} else {
|
|
sact.zdooff = false;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AGSEVENT_MOUSE_WHEEL:
|
|
// back log view mode に移行
|
|
// MessageKey 待ちのときのみ
|
|
if (sact.waittype != KEYWAIT_MESSAGE) break;
|
|
if (sblog_start())
|
|
sact.waittype = KEYWAIT_BACKLOG;
|
|
break;
|
|
|
|
case AGSEVENT_BUTTON_RELEASE:
|
|
if (sact.zhiding) {
|
|
slist_foreach(sact.sp_zhide, cb_focused_zkey, &update);
|
|
sact.zhiding = false;
|
|
}
|
|
// fall through
|
|
|
|
case AGSEVENT_KEY_RELEASE:
|
|
switch(e->code) {
|
|
case KEY_Z:
|
|
cur = sys_get_ticks();
|
|
if (500 < (cur - sact.zofftime) || !sact.zdooff) {
|
|
slist_foreach(sact.sp_zhide, cb_focused_zkey, &update);
|
|
sact.zhiding = false;
|
|
}
|
|
break;
|
|
case KEY_PAGEUP:
|
|
case KEY_PAGEDOWN:
|
|
// MessageKey 待ちのときのみ
|
|
if (sact.waittype != KEYWAIT_MESSAGE) break;
|
|
if (sblog_start())
|
|
sact.waittype = KEYWAIT_BACKLOG;
|
|
break;
|
|
default:
|
|
sact.waitkey = e->code;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (update) {
|
|
sp_update_clipped();
|
|
}
|
|
}
|
|
|
|
/*
|
|
WaitKeySpriteのcallback
|
|
*/
|
|
EMSCRIPTEN_KEEPALIVE
|
|
void cb_waitkey_sprite(agsevent_t *e) {
|
|
SList *node;
|
|
sprite_t *focused_sp = NULL; // focus を得ている sprite
|
|
sprite_t *defocused_sp = NULL; // focus を失った sprite
|
|
int update = 0;
|
|
|
|
// キーイベントは無視
|
|
switch(e->type) {
|
|
case AGSEVENT_KEY_RELEASE:
|
|
case AGSEVENT_KEY_PRESS:
|
|
return;
|
|
}
|
|
|
|
if (sact.draggedsp) {
|
|
// 先に drag中のspriteにイベントを送る
|
|
update = sact.draggedsp->eventcb(sact.draggedsp, e); // Async in emscripten
|
|
} else {
|
|
// 右クリックキャンセル
|
|
// drag中でない時のみ、キャンセルを受け付ける
|
|
if (e->type == AGSEVENT_BUTTON_RELEASE &&
|
|
e->code == AGSEVENT_BUTTON_RIGHT) {
|
|
sact.waitkey = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// forcusを得ている sprite と focusを失った sprite を探す
|
|
for (node = sact.eventlisteners; node; node = node->next) {
|
|
sprite_t *sp = (sprite_t *)node->data;
|
|
|
|
if (sp == NULL) continue;
|
|
if (!sp->show) continue;
|
|
|
|
// freeze状態ではCGは変化しない
|
|
if (sp->freezed_state != 0) continue;
|
|
|
|
// dragg中の sprite は無視する
|
|
if (sp == sact.draggedsp) continue;
|
|
|
|
if (focused_sp == NULL && sp_is_insprite(sp, e->mousex, e->mousey)) {
|
|
/*
|
|
focusを得ている sprite
|
|
*/
|
|
update += cb_focused(sp);
|
|
focused_sp = sp;
|
|
} else {
|
|
/*
|
|
現在のカーソル位置にはいま処理している番号のsprite
|
|
は存在しないので、defocus の処理を行う。
|
|
今回のマウス移動イベントによりfocusを失ったので
|
|
あれば、cb_decocused(sp)は 1 を返す
|
|
*/
|
|
int ret = cb_defocused(sp);
|
|
if (ret > 0) defocused_sp = sp;
|
|
update += ret;
|
|
}
|
|
}
|
|
|
|
// focusを得た sprite に BUTTONイベントのみを送る
|
|
if (focused_sp && e->type != AGSEVENT_MOUSE_MOTION) {
|
|
update += focused_sp->eventcb(focused_sp, e);
|
|
}
|
|
|
|
// 範囲外(focusを得ているspriteがない場合)をクリックしたときの音
|
|
if (!focused_sp &&
|
|
e->type != AGSEVENT_MOUSE_MOTION &&
|
|
sact.numsoundob) {
|
|
ssnd_play(sact.numsoundob);
|
|
}
|
|
|
|
// drag中でない場合は、説明スプライトの表示、消去を行う
|
|
if (sact.draggedsp == NULL && e->type == AGSEVENT_MOUSE_MOTION) {
|
|
// focus を失った sprite の 説明 sprite の消去
|
|
if (defocused_sp) {
|
|
sprite_t *sp = defocused_sp;
|
|
if (sp->expsp) {
|
|
slist_foreach(sp->expsp, cb_defocused_swsp, &update);
|
|
}
|
|
}
|
|
|
|
// focus を得た sprite の 説明 sprite の表示
|
|
if (focused_sp) {
|
|
sprite_t *sp = focused_sp;
|
|
if (sp->expsp) {
|
|
slist_foreach(sp->expsp, cb_focused_swsp, &update);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 表示状態に変更があればその領域を更新
|
|
if (update) {
|
|
sp_update_clipped();
|
|
}
|
|
}
|
|
|
|
/*
|
|
選択肢 Window Open 時の callback
|
|
*/
|
|
static void cb_waitkey_selection(agsevent_t *e) {
|
|
switch (e->type) {
|
|
case AGSEVENT_BUTTON_RELEASE:
|
|
sact.sel.cbrelease(e);
|
|
break;
|
|
|
|
case AGSEVENT_MOUSE_MOTION:
|
|
sact.sel.cbmove(e);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
バックログ参照時
|
|
*/
|
|
static void cb_waitkey_backlog(agsevent_t *e) {
|
|
switch (e->type) {
|
|
case AGSEVENT_KEY_RELEASE:
|
|
switch (e->code) {
|
|
case KEY_ESCAPE:
|
|
sblog_end();
|
|
sact.waittype = KEYWAIT_MESSAGE;
|
|
break;
|
|
case KEY_PAGEUP:
|
|
sblog_pageup();
|
|
break;
|
|
case KEY_PAGEDOWN:
|
|
sblog_pagedown();
|
|
break;
|
|
case KEY_UP:
|
|
sblog_pagenext();
|
|
break;
|
|
case KEY_DOWN:
|
|
sblog_pagepre();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case AGSEVENT_BUTTON_RELEASE:
|
|
if (e->code == AGSEVENT_BUTTON_RIGHT) {
|
|
sblog_end();
|
|
sact.waittype = KEYWAIT_MESSAGE;
|
|
}
|
|
break;
|
|
|
|
case AGSEVENT_MOUSE_WHEEL:
|
|
if (e->code > 0)
|
|
sblog_pagenext();
|
|
else
|
|
sblog_pagepre();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
X|SDL のイベントディスパッチャからくる最初の場所
|
|
*/
|
|
void spev_callback(agsevent_t *e) {
|
|
if (sact.waittype != KEYWAIT_BACKLOG) {
|
|
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
|
sact.waitskiplv = 2;
|
|
sact.waitkey = e->code;
|
|
return;
|
|
}
|
|
|
|
if (e->type == AGSEVENT_KEY_RELEASE && e->code == KEY_CTRL) {
|
|
sact.waitskiplv = 0;
|
|
sact.waitkey = e->code;
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (sact.waittype) {
|
|
case KEYWAIT_MESSAGE:
|
|
case KEYWAIT_SIMPLE:
|
|
cb_waitkey_simple(e);
|
|
break;
|
|
|
|
case KEYWAIT_SPRITE:
|
|
cb_waitkey_sprite(e);
|
|
break;
|
|
|
|
case KEYWAIT_SELECT:
|
|
cb_waitkey_selection(e);
|
|
break;
|
|
|
|
case KEYWAIT_BACKLOG:
|
|
cb_waitkey_backlog(e);
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
各スプライト毎のイベント callback の登録
|
|
*/
|
|
void spev_add_eventlistener(sprite_t *sp, int (*cb)(sprite_t *, agsevent_t *)) {
|
|
sp->eventcb = cb;
|
|
sact.eventlisteners = slist_append(sact.eventlisteners, sp);
|
|
}
|
|
|
|
/*
|
|
上で登録した callback の削除
|
|
*/
|
|
void spev_remove_eventlistener(sprite_t *sp) {
|
|
sact.eventlisteners = slist_remove(sact.eventlisteners, sp);
|
|
}
|
|
|