@ -51,16 +51,20 @@ using namespace DFHack;
# include "dfhack/SDL_fakes/events.h"
# include "dfhack/SDL_fakes/events.h"
# include "dfhack/df/ui.h"
# include "dfhack/df/world.h"
# include "dfhack/df/world.h"
# include "dfhack/df/world_data.h"
# include "dfhack/df/world_data.h"
# include "dfhack/df/interface.h"
# include "dfhack/df/viewscreen_dwarfmodest.h"
# include <stdio.h>
# include <stdio.h>
# include <iomanip>
# include <iomanip>
# include <stdlib.h>
# include <stdlib.h>
# include <fstream>
# include <fstream>
# include "tinythread.h"
# include "tinythread.h"
using namespace tthread ;
using namespace tthread ;
using namespace df : : enums ;
struct Core : : Cond
struct Core : : Cond
{
{
@ -204,6 +208,7 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
" cls - Clear the console. \n "
" cls - Clear the console. \n "
" fpause - Force DF to pause. \n "
" fpause - Force DF to pause. \n "
" die - Force DF to close immediately \n "
" die - Force DF to close immediately \n "
" keybinding - Modify bindings of commands to keys \n "
" Plugin management (useful for developers): \n "
" Plugin management (useful for developers): \n "
//" belongs COMMAND - Tell which plugin a command belongs to.\n"
//" belongs COMMAND - Tell which plugin a command belongs to.\n"
" plug [PLUGIN|v] - List plugin state and description. \n "
" plug [PLUGIN|v] - List plugin state and description. \n "
@ -212,6 +217,27 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
" reload PLUGIN|all - Reload a plugin or all loaded plugins. \n "
" reload PLUGIN|all - Reload a plugin or all loaded plugins. \n "
) ;
) ;
}
}
else if ( parts . size ( ) = = 1 )
{
Plugin * plug = plug_mgr - > getPluginByCommand ( parts [ 0 ] ) ;
if ( plug ) {
for ( int j = 0 ; j < plug - > size ( ) ; j + + )
{
const PluginCommand & pcmd = ( plug - > operator [ ] ( j ) ) ;
if ( pcmd . name ! = parts [ 0 ] )
continue ;
if ( pcmd . isHotkeyCommand ( ) )
con . color ( Console : : COLOR_CYAN ) ;
con . print ( " %s: %s \n " , pcmd . name . c_str ( ) , pcmd . description . c_str ( ) ) ;
con . reset_color ( ) ;
if ( ! pcmd . usage . empty ( ) )
con < < " Usage: \n " < < pcmd . usage < < flush ;
return ;
}
}
con . printerr ( " Unknown command: %s \n " , parts [ 0 ] . c_str ( ) ) ;
}
else
else
{
{
con . printerr ( " not implemented yet \n " ) ;
con . printerr ( " not implemented yet \n " ) ;
@ -311,7 +337,10 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
else for ( int j = 0 ; j < plug - > size ( ) ; j + + )
else for ( int j = 0 ; j < plug - > size ( ) ; j + + )
{
{
const PluginCommand & pcmd = ( plug - > operator [ ] ( j ) ) ;
const PluginCommand & pcmd = ( plug - > operator [ ] ( j ) ) ;
if ( pcmd . isHotkeyCommand ( ) )
con . color ( Console : : COLOR_CYAN ) ;
con . print ( " %-22s - %s \n " , pcmd . name . c_str ( ) , pcmd . description . c_str ( ) ) ;
con . print ( " %-22s - %s \n " , pcmd . name . c_str ( ) , pcmd . description . c_str ( ) ) ;
con . reset_color ( ) ;
}
}
}
}
else
else
@ -339,7 +368,10 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
for ( int j = 0 ; j < plug - > size ( ) ; j + + )
for ( int j = 0 ; j < plug - > size ( ) ; j + + )
{
{
const PluginCommand & pcmd = ( plug - > operator [ ] ( j ) ) ;
const PluginCommand & pcmd = ( plug - > operator [ ] ( j ) ) ;
if ( pcmd . isHotkeyCommand ( ) )
con . color ( Console : : COLOR_CYAN ) ;
con . print ( " %-22s- %s \n " , pcmd . name . c_str ( ) , pcmd . description . c_str ( ) ) ;
con . print ( " %-22s- %s \n " , pcmd . name . c_str ( ) , pcmd . description . c_str ( ) ) ;
con . reset_color ( ) ;
}
}
}
}
}
}
@ -354,6 +386,49 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
con . print ( " %s \n " , plug - > getName ( ) . c_str ( ) ) ;
con . print ( " %s \n " , plug - > getName ( ) . c_str ( ) ) ;
}
}
}
}
else if ( first = = " keybinding " )
{
if ( parts . size ( ) > = 3 & & ( parts [ 0 ] = = " set " | | parts [ 0 ] = = " add " ) )
{
std : : string keystr = parts [ 1 ] ;
if ( parts [ 0 ] = = " set " )
core - > ClearKeyBindings ( keystr ) ;
for ( int i = parts . size ( ) - 1 ; i > = 2 ; i - - )
{
if ( ! core - > AddKeyBinding ( keystr , parts [ i ] ) ) {
con . printerr ( " Invalid key spec: %s \n " , keystr . c_str ( ) ) ;
break ;
}
}
}
else if ( parts . size ( ) > = 2 & & parts [ 0 ] = = " clear " )
{
for ( unsigned i = 1 ; i < parts . size ( ) ; i + + )
{
if ( ! core - > ClearKeyBindings ( parts [ i ] ) ) {
con . printerr ( " Invalid key spec: %s \n " , parts [ i ] . c_str ( ) ) ;
break ;
}
}
}
else if ( parts . size ( ) = = 2 & & parts [ 0 ] = = " list " )
{
std : : vector < std : : string > list = core - > ListKeyBindings ( parts [ 1 ] ) ;
if ( list . empty ( ) )
con < < " No bindings. " < < endl ;
for ( unsigned i = 0 ; i < list . size ( ) ; i + + )
con < < " " < < list [ i ] < < endl ;
}
else
{
con < < " Usage: " < < endl
< < " keybinding list <key> " < < endl
< < " keybinding clear <key> <key>... " < < endl
< < " keybinding set <key> \" cmdline \" \" cmdline \" ... " < < endl
< < " keybinding add <key> \" cmdline \" \" cmdline \" ... " < < endl
< < " Later adds, and earlier items within one command have priority. " < < endl ;
}
}
else if ( first = = " fpause " )
else if ( first = = " fpause " )
{
{
World * w = core - > getWorld ( ) ;
World * w = core - > getWorld ( ) ;
@ -482,12 +557,12 @@ Core::Core()
StackMutex = 0 ;
StackMutex = 0 ;
core_cond = 0 ;
core_cond = 0 ;
// set up hotkey capture
// set up hotkey capture
memset ( hotkey_states , 0 , sizeof ( hotkey_states ) ) ;
hotkey_set = false ;
hotkey_set = false ;
HotkeyMutex = 0 ;
HotkeyMutex = 0 ;
HotkeyCond = 0 ;
HotkeyCond = 0 ;
misc_data_mutex = 0 ;
misc_data_mutex = 0 ;
last_world_data_ptr = NULL ;
last_world_data_ptr = NULL ;
top_viewscreen = NULL ;
} ;
} ;
void Core : : fatal ( std : : string output , bool deactivate )
void Core : : fatal ( std : : string output , bool deactivate )
@ -694,6 +769,19 @@ int Core::Update()
plug_mgr - > OnStateChange ( new_wdata ? SC_GAME_LOADED : SC_GAME_UNLOADED ) ;
plug_mgr - > OnStateChange ( new_wdata ? SC_GAME_LOADED : SC_GAME_UNLOADED ) ;
}
}
// detect if the viewscreen changed
if ( df : : global : : gview )
{
df : : viewscreen * screen = & df : : global : : gview - > view ;
while ( screen - > child )
screen = screen - > child ;
if ( screen ! = top_viewscreen )
{
top_viewscreen = screen ;
plug_mgr - > OnStateChange ( SC_VIEWSCREEN_CHANGED ) ;
}
}
// notify all the plugins that a game tick is finished
// notify all the plugins that a game tick is finished
plug_mgr - > OnUpdate ( ) ;
plug_mgr - > OnUpdate ( ) ;
@ -785,37 +873,166 @@ int Core::SDL_Event(SDL::Event* ev, int orig_return)
if ( ev & & ev - > type = = SDL : : ET_KEYDOWN | | ev - > type = = SDL : : ET_KEYUP )
if ( ev & & ev - > type = = SDL : : ET_KEYDOWN | | ev - > type = = SDL : : ET_KEYUP )
{
{
SDL : : KeyboardEvent * ke = ( SDL : : KeyboardEvent * ) ev ;
SDL : : KeyboardEvent * ke = ( SDL : : KeyboardEvent * ) ev ;
bool shift = ke - > ksym . mod & SDL : : KMOD_SHIFT ;
// consuming F1 .. F8
if ( ke - > state = = SDL : : BTN_PRESSED & & ! hotkey_states [ ke - > ksym . sym ] )
int idx = ke - > ksym . sym - SDL : : K_F1 ;
if ( idx < 0 | | idx > 7 )
return orig_return ;
idx + = 8 * shift ;
// now we have the real index...
if ( ke - > state = = SDL : : BTN_PRESSED & & ! hotkey_states [ idx ] )
{
{
hotkey_states [ idx ] = 1 ;
hotkey_states [ ke - > ksym . sym ] = true ;
Gui * g = getGui ( ) ;
if ( g - > hotkeys & & g - > df_interface & & g - > df_menu_state )
int mod = 0 ;
if ( ke - > ksym . mod & SDL : : KMOD_SHIFT ) mod | = 1 ;
if ( ke - > ksym . mod & SDL : : KMOD_CTRL ) mod | = 2 ;
if ( ke - > ksym . mod & SDL : : KMOD_ALT ) mod | = 4 ;
SelectHotkey ( ke - > ksym . sym , mod ) ;
}
else if ( ke - > state = = SDL : : BTN_RELEASED )
{
{
t_viewscreen * ws = g - > GetCurrentScreen ( ) ;
hotkey_states [ ke - > ksym . sym ] = false ;
// FIXME: put hardcoded values into memory.xml
}
if ( ws - > getClassName ( ) = = " viewscreen_dwarfmodest " & & * g - > df_menu_state = = 0x23 )
}
return orig_return ;
return orig_return ;
// do stuff with the events...
}
bool Core : : SelectHotkey ( int sym , int modifiers )
{
// Find the topmost viewscreen
if ( ! df : : global : : gview | | ! df : : global : : ui )
return false ;
df : : viewscreen * screen = & df : : global : : gview - > view ;
while ( screen - > child )
screen = screen - > child ;
std : : string cmd ;
{
tthread : : lock_guard < tthread : : mutex > lock ( * HotkeyMutex ) ;
// Check the internal keybindings
std : : vector < KeyBinding > & bindings = key_bindings [ sym ] ;
for ( int i = bindings . size ( ) - 1 ; i > = 0 ; - - i ) {
if ( bindings [ i ] . modifiers ! = modifiers )
continue ;
if ( ! plug_mgr - > CanInvokeHotkey ( bindings [ i ] . command [ 0 ] , screen ) )
continue ;
cmd = bindings [ i ] . cmdline ;
break ;
}
if ( cmd . empty ( ) ) {
// Check the hotkey keybindings
int idx = sym - SDL : : K_F1 ;
if ( idx > = 0 & & idx < 8 )
{
if ( modifiers & 1 )
idx + = 8 ;
if ( ! strict_virtual_cast < df : : viewscreen_dwarfmodest > ( screen ) | |
df : : global : : ui - > main . mode ! = ui_sidebar_mode : : Hotkeys )
{
cmd = df : : global : : ui - > main . hotkeys [ idx ] . name ;
}
}
}
}
if ( ! cmd . empty ( ) ) {
setHotkeyCmd ( cmd ) ;
return true ;
}
else
else
return false ;
}
static bool parseKeySpec ( std : : string keyspec , int * psym , int * pmod )
{
{
t_hotkey & hotkey = ( * g - > hotkeys ) [ idx ] ;
* pmod = 0 ;
setHotkeyCmd ( hotkey . name ) ;
// ugh, ugly
for ( ; ; ) {
if ( keyspec . size ( ) > 6 & & keyspec . substr ( 0 , 6 ) = = " Shift- " ) {
* pmod | = 1 ;
keyspec = keyspec . substr ( 6 ) ;
} else if ( keyspec . size ( ) > 5 & & keyspec . substr ( 0 , 5 ) = = " Ctrl- " ) {
* pmod | = 2 ;
keyspec = keyspec . substr ( 5 ) ;
} else if ( keyspec . size ( ) > 4 & & keyspec . substr ( 0 , 4 ) = = " Alt- " ) {
* pmod | = 4 ;
keyspec = keyspec . substr ( 4 ) ;
} else
break ;
}
}
if ( keyspec . size ( ) = = 1 & & keyspec [ 0 ] > = ' A ' & & keyspec [ 0 ] < = ' Z ' ) {
* psym = SDL : : K_a + ( keyspec [ 0 ] - ' A ' ) ;
return true ;
} else if ( keyspec . size ( ) = = 2 & & keyspec [ 0 ] = = ' F ' & & keyspec [ 1 ] > = ' 1 ' & & keyspec [ 1 ] < = ' 9 ' ) {
* psym = SDL : : K_F1 + ( keyspec [ 1 ] - ' 1 ' ) ;
return true ;
} else
return false ;
}
}
bool Core : : ClearKeyBindings ( std : : string keyspec )
{
int sym , mod ;
if ( ! parseKeySpec ( keyspec , & sym , & mod ) )
return false ;
tthread : : lock_guard < tthread : : mutex > lock ( * HotkeyMutex ) ;
std : : vector < KeyBinding > & bindings = key_bindings [ sym ] ;
for ( int i = bindings . size ( ) - 1 ; i > = 0 ; - - i ) {
if ( bindings [ i ] . modifiers = = mod )
bindings . erase ( bindings . begin ( ) + i ) ;
}
}
else if ( ke - > state = = SDL : : BTN_RELEASED )
return true ;
}
bool Core : : AddKeyBinding ( std : : string keyspec , std : : string cmdline )
{
{
hotkey_states [ idx ] = 0 ;
int sym ;
KeyBinding binding ;
if ( ! parseKeySpec ( keyspec , & sym , & binding . modifiers ) )
return false ;
cheap_tokenise ( cmdline , binding . command ) ;
if ( binding . command . empty ( ) )
return false ;
tthread : : lock_guard < tthread : : mutex > lock ( * HotkeyMutex ) ;
// Don't add duplicates
std : : vector < KeyBinding > & bindings = key_bindings [ sym ] ;
for ( int i = bindings . size ( ) - 1 ; i > = 0 ; - - i ) {
if ( bindings [ i ] . modifiers = = binding . modifiers & &
bindings [ i ] . cmdline = = cmdline )
return true ;
}
}
binding . cmdline = cmdline ;
bindings . push_back ( binding ) ;
return true ;
}
}
return orig_return ;
// do stuff with the events...
std : : vector < std : : string > Core : : ListKeyBindings ( std : : string keyspec )
{
int sym , mod ;
std : : vector < std : : string > rv ;
if ( ! parseKeySpec ( keyspec , & sym , & mod ) )
return rv ;
tthread : : lock_guard < tthread : : mutex > lock ( * HotkeyMutex ) ;
std : : vector < KeyBinding > & bindings = key_bindings [ sym ] ;
for ( int i = bindings . size ( ) - 1 ; i > = 0 ; - - i ) {
if ( bindings [ i ] . modifiers = = mod )
rv . push_back ( bindings [ i ] . cmdline ) ;
}
return rv ;
}
}
////////////////
////////////////