2002-01-08 21:45:49 +00:00
// Keys.cc for Fluxbox - an X11 Window manager
2006-02-16 06:53:05 +00:00
// Copyright (c) 2001 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
2001-12-11 20:47:02 +00:00
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
2004-11-19 11:37:27 +00:00
//$Id$
2001-12-11 20:47:02 +00:00
2001-12-29 10:32:04 +00:00
# include "Keys.hh"
2002-08-11 21:21:06 +00:00
2003-09-06 13:58:06 +00:00
# include "FbTk/StringUtil.hh"
# include "FbTk/App.hh"
# include "FbTk/Command.hh"
2003-06-30 14:57:14 +00:00
# include "CommandParser.hh"
2004-06-07 11:46:05 +00:00
# include "FbTk/I18n.hh"
2001-12-29 10:32:04 +00:00
2002-08-11 21:21:06 +00:00
# ifdef HAVE_CONFIG_H
2003-04-26 18:27:56 +00:00
# include "config.h"
2002-08-11 21:21:06 +00:00
# endif // HAVE_CONFIG_H
2001-12-11 20:47:02 +00:00
2002-05-02 07:10:03 +00:00
# ifdef HAVE_CTYPE_H
# include <ctype.h>
2002-02-21 00:39:08 +00:00
# endif // HAVE_CTYPE_H
2001-12-11 20:47:02 +00:00
2004-08-31 15:26:40 +00:00
# ifdef HAVE_CSTDIO
# include <cstdio>
# else
# include <stdio.h>
# endif
# ifdef HAVE_CSTDLIB
# include <cstdlib>
# else
# include <stdlib.h>
# endif
# ifdef HAVE_CERRNO
# include <cerrno>
# else
# include <errno.h>
# endif
# ifdef HAVE_CSTRING
# include <cstring>
# else
# include <string.h>
# endif
2001-12-11 20:47:02 +00:00
2002-05-02 07:10:03 +00:00
# ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
2002-02-21 00:39:08 +00:00
# endif // HAVE_SYS_TYPES_H
2001-12-11 20:47:02 +00:00
2002-05-02 07:10:03 +00:00
# ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
2002-02-21 00:39:08 +00:00
# endif // HAVE_SYS_WAIT_H
2001-12-11 20:47:02 +00:00
2002-05-02 07:10:03 +00:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
2002-02-21 00:39:08 +00:00
# endif // HAVE_UNISTD_H
2001-12-11 20:47:02 +00:00
2002-05-02 07:10:03 +00:00
# ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
2002-02-21 00:39:08 +00:00
# endif // HAVE_SYS_STAT_H
2001-12-11 20:47:02 +00:00
# include <X11/Xlib.h>
# include <X11/Xproto.h>
# include <X11/keysym.h>
2005-05-06 09:22:53 +00:00
# include <X11/Xutil.h>
# include <X11/XKBlib.h>
2001-12-11 20:47:02 +00:00
# include <iostream>
# include <fstream>
2002-01-07 23:44:09 +00:00
# include <vector>
2006-04-12 15:51:37 +00:00
# include <map>
2002-01-08 12:13:25 +00:00
# include <memory>
2001-12-11 20:47:02 +00:00
2006-10-27 06:57:43 +00:00
using std : : cerr ;
using std : : endl ;
using std : : string ;
using std : : vector ;
using std : : ifstream ;
2001-12-11 20:47:02 +00:00
2006-04-12 15:51:37 +00:00
Keys : : Keys ( ) :
2003-10-05 07:20:47 +00:00
m_display ( FbTk : : App : : instance ( ) - > display ( ) )
{
2003-08-19 16:19:28 +00:00
2001-12-11 20:47:02 +00:00
}
2005-05-06 09:22:53 +00:00
Keys : : ~ Keys ( ) {
2003-09-06 13:58:06 +00:00
2003-10-05 07:20:47 +00:00
FbTk : : KeyUtil : : ungrabKeys ( ) ;
2002-12-01 13:42:15 +00:00
deleteTree ( ) ;
2001-12-11 20:47:02 +00:00
}
2001-12-29 10:32:04 +00:00
2003-08-19 16:19:28 +00:00
/// Destroys the keytree
2001-12-11 20:47:02 +00:00
void Keys : : deleteTree ( ) {
2006-04-12 15:51:37 +00:00
for ( keyspace_t : : iterator map_it = m_map . begin ( ) ; map_it ! = m_map . end ( ) ; + + map_it ) {
keylist_t : : iterator it = map_it - > second - > begin ( ) ;
const keylist_t : : iterator it_end = map_it - > second - > end ( ) ;
for ( ; it ! = it_end ; it + + )
delete * it ;
map_it - > second - > clear ( ) ;
delete map_it - > second ;
}
2006-04-22 15:37:04 +00:00
m_map . clear ( ) ;
2001-12-11 20:47:02 +00:00
}
2001-12-29 10:32:04 +00:00
2005-05-06 09:22:53 +00:00
/**
2003-02-28 23:55:37 +00:00
Load and grab keys
TODO : error checking
@ return true on success else false
*/
2002-07-27 18:03:39 +00:00
bool Keys : : load ( const char * filename ) {
2002-12-01 13:42:15 +00:00
if ( ! filename )
return false ;
2005-05-06 09:22:53 +00:00
2002-12-01 13:42:15 +00:00
//ungrab all keys
2003-10-05 07:20:47 +00:00
FbTk : : KeyUtil : : ungrabKeys ( ) ;
2002-08-11 21:21:06 +00:00
2002-12-01 13:42:15 +00:00
//free memory of previous grabs
deleteTree ( ) ;
2002-08-11 21:21:06 +00:00
2006-04-12 15:51:37 +00:00
m_map [ " default: " ] = new keylist_t ;
2003-12-04 21:31:02 +00:00
FbTk : : App : : instance ( ) - > sync ( false ) ;
2005-05-06 09:22:53 +00:00
2002-12-01 13:42:15 +00:00
//open the file
ifstream infile ( filename ) ;
if ( ! infile )
return false ; // faild to open file
2002-08-11 21:21:06 +00:00
2003-12-20 17:37:57 +00:00
m_current_line = 0 ; //current line, so we can tell the user where the fault is
2001-12-11 20:47:02 +00:00
2002-12-01 13:42:15 +00:00
while ( ! infile . eof ( ) ) {
string linebuffer ;
2002-08-11 21:21:06 +00:00
2002-12-01 13:42:15 +00:00
getline ( infile , linebuffer ) ;
2001-12-11 20:47:02 +00:00
2003-12-20 17:37:57 +00:00
m_current_line + + ;
2002-08-11 21:21:06 +00:00
2003-12-20 17:37:57 +00:00
addBinding ( linebuffer ) ;
} // end while eof
m_current_line = 0 ;
m_filename = filename ;
2006-04-12 15:51:37 +00:00
m_keylist = m_map [ " default: " ] ;
2003-12-20 17:37:57 +00:00
return true ;
}
bool Keys : : save ( const char * filename ) const {
//!!
2005-05-06 09:22:53 +00:00
//!! TODO: fix keybinding saving
//!! (we probably need to save key actions
2003-12-20 17:37:57 +00:00
//!! as strings instead of creating new Commands)
// open file for writing
// ofstream outfile(filename);
// if (!outfile)
return false ;
// return true;
}
2006-10-27 06:57:43 +00:00
bool Keys : : addBinding ( const string & linebuffer ) {
2003-12-20 17:37:57 +00:00
vector < string > val ;
// Parse arguments
FbTk : : StringUtil : : stringtok ( val , linebuffer . c_str ( ) ) ;
// must have at least 1 argument
if ( val . size ( ) < = 0 )
return true ; // empty lines are valid.
2005-05-06 09:22:53 +00:00
2004-02-20 09:29:07 +00:00
if ( val [ 0 ] [ 0 ] = = ' # ' | | val [ 0 ] [ 0 ] = = ' ! ' ) //the line is commented
2003-12-20 17:37:57 +00:00
return true ; // still a valid line.
2005-05-06 09:22:53 +00:00
2003-12-20 17:37:57 +00:00
unsigned int key = 0 , mod = 0 ;
t_key * current_key = 0 , * last_key = 0 ;
2006-04-12 15:51:37 +00:00
size_t argc = 0 ;
2006-10-27 06:57:43 +00:00
string keyMode = " default: " ;
2006-04-12 15:51:37 +00:00
if ( val [ 0 ] [ val [ 0 ] . length ( ) - 1 ] = = ' : ' ) {
argc + + ;
keyspace_t : : iterator it = m_map . find ( val [ 0 ] ) ;
if ( it = = m_map . end ( ) )
m_map [ val [ 0 ] ] = new keylist_t ;
keyMode = val [ 0 ] ;
}
2004-06-07 11:46:05 +00:00
_FB_USES_NLS ;
2005-05-06 09:22:53 +00:00
// for each argument
2006-04-12 15:51:37 +00:00
for ( ; argc < val . size ( ) ; argc + + ) {
2003-12-20 17:37:57 +00:00
if ( val [ argc ] [ 0 ] ! = ' : ' ) { // parse key(s)
2006-04-12 15:51:37 +00:00
int tmpmod = FbTk : : KeyUtil : : getModifier ( val [ argc ] . c_str ( ) ) ;
if ( tmpmod )
mod | = tmpmod ; //If it's a modifier
else if ( strcasecmp ( " NONE " , val [ argc ] . c_str ( ) ) = = 0 )
mod = 0 ;
else {
// keycode covers the following three two-byte cases:
// 0x - hex
// +[1-9] - number between +1 and +9
// numbers 10 and above
//
2006-10-27 06:57:43 +00:00
if ( val [ argc ] . size ( ) > 1 & & ( isdigit ( val [ argc ] [ 0 ] ) & &
( isdigit ( val [ argc ] [ 1 ] ) | | val [ argc ] [ 1 ] = = ' x ' ) | |
2006-04-12 15:51:37 +00:00
val [ argc ] [ 0 ] = = ' + ' & & isdigit ( val [ argc ] [ 1 ] ) ) ) {
2006-10-27 06:57:43 +00:00
2006-04-12 15:51:37 +00:00
key = strtoul ( val [ argc ] . c_str ( ) , NULL , 0 ) ;
2005-05-20 22:25:22 +00:00
2006-04-12 15:51:37 +00:00
if ( errno = = EINVAL | | errno = = ERANGE )
key = 0 ;
2005-05-20 22:25:22 +00:00
2006-04-12 15:51:37 +00:00
} else // convert from string symbol
2006-10-27 06:57:43 +00:00
key = FbTk : : KeyUtil : : getKey ( val [ argc ] . c_str ( ) ) ;
2005-05-20 22:25:22 +00:00
2006-04-12 15:51:37 +00:00
if ( key = = 0 ) {
2006-10-27 06:57:43 +00:00
cerr < < _FB_CONSOLETEXT ( Keys , InvalidKeyMod ,
" Keys: Invalid key/modifier on line " ,
2006-04-12 15:51:37 +00:00
" A bad key/modifier string was found on line (number following) " ) < < " " < <
m_current_line < < " ): " < < linebuffer < < endl ;
return false ;
}
if ( ! current_key ) {
current_key = new t_key ( key , mod ) ;
last_key = current_key ;
} else {
t_key * temp_key = new t_key ( key , mod ) ;
last_key - > keylist . push_back ( temp_key ) ;
last_key = temp_key ;
2003-07-02 05:42:21 +00:00
}
2005-05-06 09:22:53 +00:00
}
2003-06-30 19:42:20 +00:00
2003-12-20 17:37:57 +00:00
} else { // parse command line
if ( last_key = = 0 ) {
2006-06-21 14:41:16 +00:00
cerr < < _FB_CONSOLETEXT ( Keys , BadLine , " Keys: Error on line " , " Error on line (number following) " ) < < " : " < < m_current_line < < endl ;
2003-12-20 17:37:57 +00:00
cerr < < " > " < < linebuffer < < endl ;
return false ;
}
bool ret_val = true ;
2005-05-06 09:22:53 +00:00
const char * str =
2003-12-20 17:37:57 +00:00
FbTk : : StringUtil : : strcasestr ( linebuffer . c_str ( ) ,
val [ argc ] . c_str ( ) + 1 ) ; // +1 to skip ':'
if ( str = = 0 ) {
2006-06-21 14:41:16 +00:00
cerr < < _FB_CONSOLETEXT ( Keys , BadLine , " Keys: Error on line " , " Error on line (number following) " ) < < " : " < < m_current_line < < endl ;
2003-12-20 17:37:57 +00:00
cerr < < " > " < < linebuffer < < endl ;
ret_val = false ;
} else {
last_key - > m_command = CommandParser : : instance ( ) . parseLine ( str ) ;
if ( * last_key - > m_command = = 0 ) {
2006-06-21 14:41:16 +00:00
cerr < < _FB_CONSOLETEXT ( Keys , BadLine , " Keys: Error on line " , " Error on line (number following) " ) < < " : " < < m_current_line < < endl ;
2003-06-30 14:57:14 +00:00
cerr < < " > " < < linebuffer < < endl ;
} else {
2006-04-12 15:51:37 +00:00
// need to change keymode here so it doesn't get changed by CommandParser
m_keylist = m_map [ keyMode ] ;
2003-12-20 17:37:57 +00:00
// Add the keychain to list
if ( ! mergeTree ( current_key ) ) {
2006-06-21 14:41:16 +00:00
cerr < < _FB_CONSOLETEXT ( Keys , BadMerge , " Keys: Failed to merge keytree! " , " relatively technical error message. Key bindings are stored in a tree structure " ) < < endl ;
2003-12-20 17:37:57 +00:00
ret_val = false ;
2003-06-30 20:59:28 +00:00
}
2002-12-01 13:42:15 +00:00
}
2003-12-20 17:37:57 +00:00
}
delete current_key ;
current_key = 0 ;
last_key = 0 ;
2003-06-30 14:57:14 +00:00
2003-12-20 17:37:57 +00:00
return ret_val ;
2002-01-21 01:48:47 +00:00
2003-12-20 17:37:57 +00:00
} // end if
} // end for
return false ;
2001-12-11 20:47:02 +00:00
}
2003-12-20 17:37:57 +00:00
2003-02-28 23:55:37 +00:00
/**
2006-04-12 15:51:37 +00:00
@ return the KeyAction of the XKeyEvent ; return false if not bound
2003-02-28 23:55:37 +00:00
*/
2006-04-12 15:51:37 +00:00
bool Keys : : doAction ( XKeyEvent & ke ) {
2005-05-06 09:22:53 +00:00
2003-12-30 18:14:33 +00:00
ke . state = FbTk : : KeyUtil : : instance ( ) . cleanMods ( ke . state ) ;
2005-05-06 09:22:53 +00:00
static struct t_key * next_key = 0 ;
2002-12-01 13:42:15 +00:00
if ( ! next_key ) {
2006-04-12 15:51:37 +00:00
bool retval = false ;
// need a local keylist, in case m_command->execute() changes it
keylist_t * keylist = m_keylist ;
for ( size_t i = 0 ; i < keylist - > size ( ) ; i + + ) {
if ( * ( * keylist ) [ i ] = = ke ) {
if ( ( * keylist ) [ i ] - > keylist . size ( ) ) {
next_key = ( * keylist ) [ i ] ;
return true ; //still counts as being grabbed
}
if ( * ( * keylist ) [ i ] - > m_command ! = 0 ) {
( * keylist ) [ i ] - > m_command - > execute ( ) ;
retval = true ;
2002-12-01 13:42:15 +00:00
}
}
}
2006-04-12 15:51:37 +00:00
return retval ;
}
t_key * temp_key = next_key - > find ( ke ) ;
if ( temp_key ) {
if ( temp_key - > keylist . size ( ) ) {
next_key = temp_key ;
return true ;
2005-05-06 09:22:53 +00:00
}
2006-04-12 15:51:37 +00:00
next_key = 0 ;
if ( * temp_key - > m_command = = 0 )
return false ;
temp_key - > m_command - > execute ( ) ;
return true ;
2002-12-01 13:42:15 +00:00
}
2006-04-12 15:51:37 +00:00
temp_key = next_key ;
next_key = 0 ;
if ( * temp_key - > m_command = = 0 )
return false ;
temp_key - > m_command - > execute ( ) ;
return true ;
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
deletes the tree and load configuration
returns true on success else false
*/
2002-07-27 18:03:39 +00:00
bool Keys : : reconfigure ( const char * filename ) {
2002-12-01 13:42:15 +00:00
return load ( filename ) ;
2001-12-11 20:47:02 +00:00
}
2003-02-28 23:55:37 +00:00
/**
Merges two chains and binds new keys
@ return true on success else false .
*/
2001-12-11 20:47:02 +00:00
bool Keys : : mergeTree ( t_key * newtree , t_key * basetree ) {
2006-04-03 05:30:21 +00:00
size_t baselist_i = 0 ;
2002-12-01 13:42:15 +00:00
if ( basetree = = 0 ) {
2006-04-12 15:51:37 +00:00
for ( ; baselist_i < m_keylist - > size ( ) ; baselist_i + + ) {
if ( ( * m_keylist ) [ baselist_i ] - > mod = = newtree - > mod & &
( * m_keylist ) [ baselist_i ] - > key = = newtree - > key ) {
if ( newtree - > keylist . size ( ) & & * ( * m_keylist ) [ baselist_i ] - > m_command = = 0 ) {
2002-12-01 13:42:15 +00:00
//assumes the newtree only have one branch
2006-04-12 15:51:37 +00:00
return mergeTree ( newtree - > keylist [ 0 ] , ( * m_keylist ) [ baselist_i ] ) ;
2002-12-01 13:42:15 +00:00
} else
break ;
}
}
2006-04-12 15:51:37 +00:00
if ( baselist_i = = m_keylist - > size ( ) ) {
2003-10-05 07:20:47 +00:00
FbTk : : KeyUtil : : grabKey ( newtree - > key , newtree - > mod ) ;
2006-04-12 15:51:37 +00:00
m_keylist - > push_back ( new t_key ( newtree ) ) ;
2002-12-01 13:42:15 +00:00
if ( newtree - > keylist . size ( ) )
2006-04-12 15:51:37 +00:00
return mergeTree ( newtree - > keylist [ 0 ] , m_keylist - > back ( ) ) ;
2002-12-01 13:42:15 +00:00
return true ;
}
2005-05-06 09:22:53 +00:00
2002-12-01 13:42:15 +00:00
} else {
for ( ; baselist_i < basetree - > keylist . size ( ) ; baselist_i + + ) {
if ( basetree - > keylist [ baselist_i ] - > mod = = newtree - > mod & &
basetree - > keylist [ baselist_i ] - > key = = newtree - > key ) {
if ( newtree - > keylist . size ( ) ) {
//assumes the newtree only have on branch
return mergeTree ( newtree - > keylist [ 0 ] , basetree - > keylist [ baselist_i ] ) ;
} else
return false ;
2005-05-06 09:22:53 +00:00
}
2002-12-01 13:42:15 +00:00
}
//if it wasn't in the list grab the key and add it to the list
2005-05-06 09:22:53 +00:00
if ( baselist_i = = basetree - > keylist . size ( ) ) {
2003-10-05 07:20:47 +00:00
FbTk : : KeyUtil : : grabKey ( newtree - > key , newtree - > mod ) ;
2002-12-01 13:42:15 +00:00
basetree - > keylist . push_back ( new t_key ( newtree ) ) ;
if ( newtree - > keylist . size ( ) )
return mergeTree ( newtree - > keylist [ 0 ] , basetree - > keylist . back ( ) ) ;
2005-05-06 09:22:53 +00:00
return true ;
}
2002-12-01 13:42:15 +00:00
}
2005-05-06 09:22:53 +00:00
2002-12-01 13:42:15 +00:00
return false ;
2001-12-11 20:47:02 +00:00
}
2006-10-27 06:57:43 +00:00
void Keys : : keyMode ( string keyMode = " default " ) {
2006-04-12 15:51:37 +00:00
keyspace_t : : iterator it = m_map . find ( keyMode + " : " ) ;
if ( it = = m_map . end ( ) )
m_keylist = m_map [ " default: " ] ;
else
m_keylist = it - > second ;
}
2003-06-30 14:57:14 +00:00
Keys : : t_key : : t_key ( unsigned int key_ , unsigned int mod_ , FbTk : : RefCount < FbTk : : Command > command ) {
2002-12-01 13:42:15 +00:00
key = key_ ;
2005-05-06 09:22:53 +00:00
mod = mod_ ;
2003-06-30 14:57:14 +00:00
m_command = command ;
2001-12-11 20:47:02 +00:00
}
Keys : : t_key : : t_key ( t_key * k ) {
2002-12-01 13:42:15 +00:00
key = k - > key ;
mod = k - > mod ;
2003-06-30 14:57:14 +00:00
m_command = k - > m_command ;
2001-12-11 20:47:02 +00:00
}
2005-05-06 09:22:53 +00:00
Keys : : t_key : : ~ t_key ( ) {
while ( ! keylist . empty ( ) ) {
2002-12-01 13:42:15 +00:00
t_key * k = keylist . back ( ) ;
if ( k ! = 0 ) { // make sure we don't have a bad key pointer
delete k ;
keylist . pop_back ( ) ;
}
}
2003-06-30 14:57:14 +00:00
2001-12-11 20:47:02 +00:00
}