1 #include "../Common/Common.h"
8 #include "DasherControl.h"
10 #include "../DasherCore/Event.h"
11 #include "../DasherCore/ModuleManager.h"
12 #include "dasher_main.h"
13 #include "../DasherCore/GameModule.h"
14 #include "../Common/Globber.cpp"
20 #include <gdk/gdkkeysyms.h>
25 // 'Private' methods (only used in this file)
26 extern "C" gint
key_release_event(GtkWidget
*widget
, GdkEventKey
*event
, gpointer user_data
);
27 extern "C" gboolean
button_press_event(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
);
28 extern "C" void realize_canvas(GtkWidget
*widget
, gpointer user_data
);
29 extern "C" gint
canvas_configure_event(GtkWidget
*widget
, GdkEventConfigure
*event
, gpointer data
);
30 extern "C" gint
key_press_event(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
);
31 extern "C" void canvas_destroy_event(GtkWidget
*pWidget
, gpointer pUserData
);
32 extern "C" gboolean
canvas_focus_event(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer data
);
33 #ifdef HAVE_GTK_CAIRO_SHOULD_DRAW_WINDOW
34 extern "C" gint
canvas_draw_event(GtkWidget
*widget
, cairo_t
*cr
, gpointer data
);
36 extern "C" gint
canvas_expose_event(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
);
39 static bool g_iTimeoutID
= 0;
41 // CDasherControl class definitions
42 CDasherControl::CDasherControl(GtkVBox
*pVBox
, GtkDasherControl
*pDasherControl
,
43 CSettingsStore
* settings
)
44 : CDashIntfScreenMsgs(settings
, &file_utils_
) {
47 m_pDasherControl
= pDasherControl
;
48 m_pVBox
= GTK_WIDGET(pVBox
);
49 pClipboard
= gtk_clipboard_get(GDK_SELECTION_CLIPBOARD
);
50 m_pCanvas
= gtk_drawing_area_new();
51 #if GTK_CHECK_VERSION (2,18,0)
52 gtk_widget_set_can_focus(m_pCanvas
, TRUE
);
54 GTK_WIDGET_SET_FLAGS(m_pCanvas
, GTK_CAN_FOCUS
);
56 gtk_widget_set_double_buffered(m_pCanvas
, FALSE
);
58 GtkWidget
*pFrame
= gtk_frame_new(NULL
);
59 gtk_frame_set_shadow_type(GTK_FRAME(pFrame
), GTK_SHADOW_IN
);
60 gtk_container_add(GTK_CONTAINER(pFrame
), m_pCanvas
);
62 gtk_box_pack_start(GTK_BOX(m_pVBox
), pFrame
, TRUE
, TRUE
, 0);
63 gtk_widget_show_all(GTK_WIDGET(m_pVBox
));
65 // Connect callbacks - note that we need to implement the callbacks
66 // as "C" style functions and pass this as user data so they can
69 g_signal_connect(m_pCanvas
, "button_press_event", G_CALLBACK(button_press_event
), this);
70 g_signal_connect(m_pCanvas
, "button_release_event", G_CALLBACK(button_press_event
), this);
71 g_signal_connect_after(m_pCanvas
, "realize", G_CALLBACK(realize_canvas
), this);
72 g_signal_connect(m_pCanvas
, "configure_event", G_CALLBACK(canvas_configure_event
), this);
73 g_signal_connect(m_pCanvas
, "destroy", G_CALLBACK(canvas_destroy_event
), this);
75 g_signal_connect(m_pCanvas
, "key-release-event", G_CALLBACK(key_release_event
), this);
76 g_signal_connect(m_pCanvas
, "key_press_event", G_CALLBACK(key_press_event
), this);
78 g_signal_connect(m_pCanvas
, "focus_in_event", G_CALLBACK(canvas_focus_event
), this);
79 #ifdef HAVE_GTK_CAIRO_SHOULD_DRAW_WINDOW
80 g_signal_connect(m_pCanvas
, "draw", G_CALLBACK(canvas_draw_event
), this);
82 g_signal_connect(m_pCanvas
, "expose_event", G_CALLBACK(canvas_expose_event
), this);
85 char *home_dir
= getenv("HOME");
86 char *user_data_dir
= new char[strlen(home_dir
) + 10];
87 sprintf(user_data_dir
, "%s/.dasher/", home_dir
);
88 m_user_data_dir
= user_data_dir
;
90 m_pScreen
= new CCanvas(m_pCanvas
);
91 ChangeScreen(m_pScreen
);
93 //This was done in old SetupUI, i.e. the first thing in Realize().
94 // TODO: Use system defaults?
95 if(GetStringParameter(SP_DASHER_FONT
) == "")
96 SetStringParameter(SP_DASHER_FONT
, "Sans 10");
98 m_pScreen
->SetFont(GetStringParameter(SP_DASHER_FONT
));
101 // m_pKeyboardHelper = new CKeyboardHelper(this);
102 // m_pKeyboardHelper->Grab(GetBoolParameter(BP_GLOBAL_KEYBOARD));
105 void CDasherControl::CreateModules() {
106 CDasherInterfaceBase::CreateModules(); //create default set first
107 // Create locally cached copies of the mouse input objects, as we
108 // need to pass coordinates to them from the timer callback
110 (CDasherMouseInput
*) RegisterModule(new CDasherMouseInput());
111 SetDefaultInputDevice(m_pMouseInput
);
113 (CDasher1DMouseInput
*)RegisterModule(new CDasher1DMouseInput());
114 RegisterModule(new CSocketInput(this, this));
117 RegisterModule(new CDasherJoystickInput(this));
118 RegisterModule(new CDasherJoystickInputDiscrete(this));
122 RegisterModule(new CDasherTiltInput(this));
127 void CDasherControl::ClearAllContext() {
128 gtk_dasher_control_clear_all_context(m_pDasherControl
);
129 //SetBuffer(0); //the editor's clear method emits a "buffer_changed" signal,
130 //which does this for us automatically.
133 std::string
CDasherControl::GetAllContext() {
134 return gtk_dasher_control_get_all_text(m_pDasherControl
);
137 int CDasherControl::GetAllContextLenght()
139 auto text
= gtk_dasher_control_get_all_text(m_pDasherControl
);
140 return g_utf8_strlen(text
.c_str(),-1);
143 std::string
CDasherControl::GetTextAroundCursor(CControlManager::EditDistance dist
) {
144 return gtk_dasher_control_get_text_around_cursor(m_pDasherControl
, dist
);
147 std::string
CDasherControl::GetContext(unsigned int iStart
, unsigned int iLength
) {
148 return gtk_dasher_control_get_context(m_pDasherControl
, iStart
, iLength
);
151 bool CDasherControl::SupportsClipboard() {
155 void CDasherControl::CopyToClipboard(const std::string
&strText
) {
156 const gchar
*the_text(strText
.c_str());
157 gtk_clipboard_set_text(pClipboard
, the_text
, strlen(the_text
));
161 bool CDasherControl::SupportsSpeech() {
162 return m_Speech
.Init();
165 void CDasherControl::Speak(const std::string
&strText
, bool bInterrupt
) {
166 string lang
= GetActiveAlphabet()->GetLanguageCode();
167 m_Speech
.Speak(strText
, bInterrupt
, lang
);
171 CDasherControl::~CDasherControl() {
173 m_pMouseInput
= NULL
;
176 if(m_p1DMouseInput
) {
177 m_p1DMouseInput
= NULL
;
180 delete[] m_user_data_dir
;
182 // if(m_pKeyboardHelper) {
183 // delete m_pKeyboardHelper;
184 // m_pKeyboardHelper = 0;
188 bool CDasherControl::FocusEvent(GtkWidget
*pWidget
, GdkEventFocus
*pEvent
) {
189 if((pEvent
->type
== GDK_FOCUS_CHANGE
) && (pEvent
->in
)) {
190 GdkEventFocus
*focusEvent
= (GdkEventFocus
*) g_malloc(sizeof(GdkEventFocus
));
191 gboolean
*returnType
;
193 focusEvent
->type
= GDK_FOCUS_CHANGE
;
194 focusEvent
->window
= (GdkWindow
*) m_pDasherControl
;
195 focusEvent
->send_event
= FALSE
;
196 focusEvent
->in
= TRUE
;
198 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl
), "focus_in_event", GTK_WIDGET(m_pDasherControl
), focusEvent
, NULL
, &returnType
);
203 void CDasherControl::SetFocus() {
204 gtk_widget_grab_focus(m_pCanvas
);
207 GArray
*CDasherControl::GetAllowedValues(int iParameter
) {
208 // Glib version of the STL based core function
210 GArray
*pRetVal(g_array_new(false, false, sizeof(gchar
*)));
212 std::vector
< std::string
> vList
;
213 GetPermittedValues(iParameter
, vList
);
215 for(std::vector
< std::string
>::iterator
it(vList
.begin()); it
!= vList
.end(); ++it
) {
216 // For internal glib reasons we need to make a variable and then
217 // pass - we can't use the iterator directly
218 const char *pTemp(it
->c_str());
219 char *pTempNew
= new char[strlen(pTemp
) + 1];
220 strcpy(pTempNew
, pTemp
);
221 g_array_append_val(pRetVal
, pTempNew
);
227 void CDasherControl::RealizeCanvas(GtkWidget
*pWidget
) {
228 // TODO: Pointless function - call directly from C callback.
230 std::cout
<< "RealizeCanvas()" << std::endl
;
232 // Start the timer loops as everything is set up.
233 // Aim for 40 frames per second, computers are getting faster.
235 if(g_iTimeoutID
== 0) {
236 g_iTimeoutID
= g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE
, 25, timer_callback
, this, NULL
);
237 // TODO: Reimplement this (or at least reimplement some kind of status reporting)
238 //g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 5000, long_timer_callback, this, NULL);
242 int CDasherControl::CanvasConfigureEvent() {
245 #if GTK_CHECK_VERSION (2,18,0)
246 gtk_widget_get_allocation(m_pCanvas
, &a
);
248 a
.width
= m_pCanvas
->allocation
.width
;
249 a
.height
= m_pCanvas
->allocation
.height
;
252 m_pScreen
->resize(a
.width
,a
.height
);
253 ScreenResized(m_pScreen
);
258 void CDasherControl::HandleEvent(int iParameter
) {
259 CDashIntfScreenMsgs::HandleEvent(iParameter
);
262 m_pScreen
->SetFont(GetStringParameter(SP_DASHER_FONT
));
265 case BP_GLOBAL_KEYBOARD
:
267 // if(m_pKeyboardHelper)
268 // m_pKeyboardHelper->Grab(GetBoolParameter(BP_GLOBAL_KEYBOARD));
271 // Convert events coming from the core to Glib signals.
272 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl
), "dasher_changed", iParameter
);
275 void CDasherControl::editOutput(const std::string
&strText
, CDasherNode
*pNode
) {
276 if (!GetGameModule()) //GameModule sets editbox directly
277 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl
), "dasher_edit_insert", strText
.c_str(), pNode
->offset());
278 CDasherInterfaceBase::editOutput(strText
, pNode
);
281 void CDasherControl::editDelete(const std::string
&strText
, CDasherNode
*pNode
) {
282 if (!GetGameModule()) //GameModule sets editbox directly
283 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl
), "dasher_edit_delete", strText
.c_str(), pNode
->offset());
284 CDasherInterfaceBase::editDelete(strText
, pNode
);
287 void CDasherControl::editConvert(CDasherNode
*pNode
) {
288 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl
), "dasher_edit_convert");
289 CDasherInterfaceBase::editConvert(pNode
);
292 void CDasherControl::editProtect(CDasherNode
*pNode
) {
293 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl
), "dasher_edit_protect");
294 CDasherInterfaceBase::editProtect(pNode
);
297 void CDasherControl::SetLockStatus(const string
&strText
, int iPercent
) {
298 DasherLockInfo sInfo
;
299 sInfo
.szMessage
= strText
.c_str();
300 sInfo
.iPercent
= iPercent
;
301 sInfo
.time
= get_time();
303 //Uniquely, the call to gtk to handle events and update the progress
304 // dialogue, also renders the canvas. So let's have a message there too...
305 CDasherInterfaceBase::SetLockStatus(strText
,iPercent
);
306 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl
), "dasher_lock_info", &sInfo
);
309 //TODO do we want to do something like this?
310 // ATM the only message is actually from the auto-speed control,
311 // so definitely _doesn't_ want to be modal; could introduce a boolean
312 // 'ok to interrupt user?' param to Message()?
313 //void CDasherControl::Message(const std::string &strText)
314 // GtkMessageDialog *pDialog = GTK_MESSAGE_DIALOG(gtk_message_dialog_new(0, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, strText.c_str()));
315 // gtk_dialog_run(GTK_DIALOG(pDialog));
316 // gtk_widget_destroy(GTK_WIDGET(pDialog));
319 unsigned int CDasherControl::ctrlMove(bool bForwards
, CControlManager::EditDistance dist
) {
320 return gtk_dasher_control_ctrl_move(m_pDasherControl
,bForwards
,dist
);
323 unsigned int CDasherControl::ctrlDelete(bool bForwards
, CControlManager::EditDistance dist
) {
324 return gtk_dasher_control_ctrl_delete(m_pDasherControl
,bForwards
,dist
);
327 class GtkGameModule
: public CGameModule
{
329 GtkGameModule(CSettingsUser
*pCreator
, CDasherInterfaceBase
*pInterface
, CDasherView
*pView
, CDasherModel
*pModel
, GtkTextBuffer
*pBuffer
)
330 : CGameModule(pCreator
, pInterface
, pView
, pModel
), m_pBuffer(pBuffer
) {
331 m_tEntered
= gtk_text_buffer_create_tag(m_pBuffer
, "entered", "foreground", "#00FF00", NULL
);
332 m_tWrong
= gtk_text_buffer_create_tag(m_pBuffer
, "wrong", "foreground", "#FF0000", "strikethrough", TRUE
, NULL
);
333 GtkTextIter start
,end
;
334 gtk_text_buffer_get_start_iter(m_pBuffer
, &start
);
335 m_mEntered
= gtk_text_buffer_create_mark(m_pBuffer
, NULL
, &start
, true);
336 gtk_text_buffer_get_end_iter(m_pBuffer
, &end
);
337 m_mTarget
= gtk_text_buffer_create_mark(m_pBuffer
, NULL
, &end
, false);
338 gtk_text_buffer_delete(m_pBuffer
, &start
, &end
);
342 GtkTextTagTable
*table
= gtk_text_buffer_get_tag_table(m_pBuffer
);
343 gtk_text_tag_table_remove(table
, m_tEntered
);
344 gtk_text_tag_table_remove(table
, m_tWrong
);
346 gtk_text_buffer_delete_mark(m_pBuffer
,m_mEntered
);
347 gtk_text_buffer_delete_mark(m_pBuffer
,m_mTarget
);
350 void ChunkGenerated() {
352 for (vector
<symbol
>::const_iterator it
=targetSyms().begin(); it
!=targetSyms().end(); it
++)
353 sText
+= m_pAlph
->GetText(*it
);
354 gtk_text_buffer_set_text(m_pBuffer
, sText
.c_str(), -1); //-1 for length = null-terminated
355 GtkTextIter start
,end
;
356 gtk_text_buffer_get_start_iter(m_pBuffer
, &start
);
357 gtk_text_buffer_move_mark(m_pBuffer
, m_mEntered
, &start
);
358 gtk_text_buffer_move_mark(m_pBuffer
, m_mTarget
, &start
);
359 gtk_text_buffer_get_end_iter(m_pBuffer
, &end
);
360 gtk_text_buffer_remove_all_tags(m_pBuffer
, &start
, &end
);
362 void HandleEvent(const Dasher::CEditEvent
*pEvt
) {
363 const int iPrev(lastCorrectSym());
364 CGameModule::HandleEvent(pEvt
);
365 if (iPrev
==lastCorrectSym()) {
366 GtkTextIter start
,end
; //of "wrong" text
367 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &start
, m_mEntered
);
368 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &end
, m_mTarget
);
369 gtk_text_buffer_delete(m_pBuffer
, &start
, &end
); //invalidates end, brings m_mEntered & m_mTarget together
370 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &start
, m_mEntered
);
371 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &end
, m_mTarget
);
372 gtk_text_buffer_insert(m_pBuffer
, &start
, m_strWrong
.c_str(), -1); //moves m_mEntered & m_mTarget apart
373 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &start
, m_mEntered
);
374 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &end
, m_mTarget
);
375 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &end
, m_mTarget
);
376 gtk_text_buffer_apply_tag(m_pBuffer
, m_tWrong
, &start
, &end
);
379 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &it
, m_mEntered
);
380 gtk_text_buffer_get_iter_at_mark(m_pBuffer
, &it2
, m_mTarget
);
381 DASHER_ASSERT(gtk_text_iter_get_offset(&it
) == gtk_text_iter_get_offset(&it2
));
382 if (iPrev
< lastCorrectSym()) {
384 DASHER_ASSERT(iPrev
== lastCorrectSym()-1);
385 gtk_text_iter_forward_chars(&it2
, 1);
386 gtk_text_buffer_apply_tag(m_pBuffer
, m_tEntered
, &it
, &it2
);
388 //correct text erased!
389 DASHER_ASSERT(iPrev
== lastCorrectSym()+1);
390 gtk_text_iter_backward_chars(&it2
, 1);
391 gtk_text_buffer_remove_tag(m_pBuffer
, m_tEntered
, &it2
, &it
);
393 gtk_text_buffer_move_mark(m_pBuffer
, m_mEntered
, &it2
);
394 gtk_text_buffer_move_mark(m_pBuffer
, m_mTarget
, &it2
);
397 void DrawText(CDasherView
*pView
) {}
399 GtkTextBuffer
*m_pBuffer
;
400 GtkTextTag
*m_tEntered
, *m_tWrong
;
401 GtkTextMark
*m_mEntered
; //just after what's been correctly entered
402 GtkTextMark
*m_mTarget
; //after any "wrong" text, before target; if no wrong chars, ==m_entered.
405 CGameModule
*CDasherControl::CreateGameModule() {
406 if (GtkTextBuffer
*buf
=gtk_dasher_control_game_text_buffer(m_pDasherControl
))
407 return new GtkGameModule(this, this, GetView(), m_pDasherModel
, buf
);
408 return CDashIntfScreenMsgs::CreateGameModule();
411 // TODO: Sort these methods out
412 void CDasherControl::ExternalKeyDown(int iKeyVal
) {
413 // if(m_pKeyboardHelper) {
414 // int iButtonID(m_pKeyboardHelper->ConvertKeycode(iKeyVal));
416 // if(iButtonID != -1)
417 // KeyDown(get_time(), iButtonID);
419 KeyDown(get_time(), iKeyVal
);
422 void CDasherControl::ExternalKeyUp(int iKeyVal
) {
423 // if(m_pKeyboardHelper) {
424 // int iButtonID(m_pKeyboardHelper->ConvertKeycode(iKeyVal));
426 // if(iButtonID != -1)
427 // KeyUp(get_time(), iButtonID);
429 KeyUp(get_time(), iKeyVal
);
432 int CDasherControl::TimerEvent() {
434 GdkWindow
*default_root_window
= gdk_get_default_root_window();
435 GdkWindow
*window
= gtk_widget_get_window(m_pCanvas
);
437 #if GTK_CHECK_VERSION (3,0,0)
438 GdkDeviceManager
*device_manager
=
439 gdk_display_get_device_manager(gdk_window_get_display(window
));
440 GdkDevice
*pointer
= gdk_device_manager_get_client_pointer(device_manager
);
442 gdk_window_get_device_position(window
, pointer
, &x
, &y
, NULL
);
444 gdk_window_get_pointer(window
, &x
, &y
, NULL
);
446 m_pMouseInput
->SetCoordinates(x
, y
);
448 #if GTK_CHECK_VERSION (3,0,0)
449 gdk_window_get_device_position(default_root_window
, pointer
, &x
, &y
, NULL
);
451 gdk_window_get_pointer(default_root_window
, &x
, &y
, NULL
);
457 #ifdef HAVE_GDK_WINDOW_GET_WIDTH
458 iRootWidth
= gdk_window_get_width (default_root_window
);
459 iRootHeight
= gdk_window_get_height(default_root_window
);
461 gdk_drawable_get_size(default_root_window
, &iRootWidth
, &iRootHeight
);
464 if(GetLongParameter(LP_YSCALE
) < 10)
465 SetLongParameter(LP_YSCALE
, 10);
467 y
= (y
- iRootHeight
/ 2);
469 m_p1DMouseInput
->SetCoordinates(y
, GetLongParameter(LP_YSCALE
));
471 NewFrame(get_time(), false);
473 // Update our UserLog object about the current mouse position
474 CUserLogBase
* pUserLog
= GetUserLogPtr();
475 if (pUserLog
!= NULL
) {
476 // We want current canvas and window coordinates so normalization
477 // is done properly with respect to the canvas.
478 GdkRectangle sWindowRect
;
479 GdkRectangle sCanvasRect
;
481 gdk_window_get_frame_extents(window
, &sWindowRect
);
483 pUserLog
->AddWindowSize(sWindowRect
.y
,
485 sWindowRect
.y
+ sWindowRect
.height
,
486 sWindowRect
.x
+ sWindowRect
.width
);
488 if (m_pScreen
!= NULL
) {
489 if (m_pScreen
->GetCanvasSize(&sCanvasRect
))
490 pUserLog
->AddCanvasSize(sCanvasRect
.y
,
492 sCanvasRect
.y
+ sCanvasRect
.height
,
493 sCanvasRect
.x
+ sCanvasRect
.width
);
498 #if GTK_CHECK_VERSION (3,0,0)
499 gdk_window_get_device_position(NULL
, pointer
, &iMouseX
, &iMouseY
, NULL
);
501 gdk_window_get_pointer(NULL
, &iMouseX
, &iMouseY
, NULL
);
504 // TODO: This sort of thing shouldn't be in specialised methods, move into base class somewhere
505 pUserLog
->AddMouseLocationNormalized(iMouseX
, iMouseY
, true, GetNats());
510 // See CVS for code which used to be here
513 int CDasherControl::LongTimerEvent() {
514 // std::cout << "Framerate: " << GetFramerate() << std::endl;
515 // std::cout << "Render count: " << GetRenderCount() << std::endl;
519 gboolean
CDasherControl::ExposeEvent() {
520 NewFrame(get_time(), true);
524 void CDasherControl::Done() {
525 CDasherInterfaceBase::Done();
526 g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl
), "dasher_stop");
529 gboolean
CDasherControl::ButtonPressEvent(GdkEventButton
*event
) {
531 // Take the focus if we click on the canvas
533 // GdkEventFocus *focusEvent = (GdkEventFocus *) g_malloc(sizeof(GdkEventFocus));
534 // gboolean *returnType;
536 // focusEvent->type = GDK_FOCUS_CHANGE;
537 // focusEvent->window = (GdkWindow *) m_pCanvas;
538 // focusEvent->send_event = FALSE;
539 // focusEvent->in = TRUE;
541 // gtk_widget_grab_focus(GTK_WIDGET(m_pCanvas));
542 // g_signal_emit_by_name(GTK_WIDGET(m_pCanvas), "focus_in_event", GTK_WIDGET(m_pCanvas), focusEvent, NULL, &returnType);
544 // No - don't take the focus - give it to the text area instead
546 //GDK uses button 1=left, 2=middle, 3=right. We want 100, 102, 101
547 int button
= event
->button
;
548 if (button
&2) button
^=1;
549 if(event
->type
== GDK_BUTTON_PRESS
)
550 KeyDown(get_time(), button
+99 );
551 else if(event
->type
== GDK_BUTTON_RELEASE
)
552 KeyUp(get_time(), button
+99);
557 gint
CDasherControl::KeyReleaseEvent(GdkEventKey
*event
) {
558 // TODO: This is seriously flawed - the semantics of of X11 Keyboard
559 // events mean the there's no guarantee that key up/down events will
560 // be received in pairs.
562 // if((event->keyval == GDK_Shift_L) || (event->keyval == GDK_Shift_R)) {
563 // if(event->state & GDK_CONTROL_MASK)
564 // SetLongParameter(LP_BOOSTFACTOR, 25);
566 // SetLongParameter(LP_BOOSTFACTOR, 100);
568 // else if((event->keyval == GDK_Control_L) || (event->keyval == GDK_Control_R)) {
569 // if(event->state & GDK_SHIFT_MASK)
570 // SetLongParameter(LP_BOOSTFACTOR, 175);
572 // SetLongParameter(LP_BOOSTFACTOR, 100);
575 // if(m_pKeyboardHelper) {
576 // int iKeyVal(m_pKeyboardHelper->ConvertKeycode(event->keyval));
579 // KeyUp(get_time(), iKeyVal);
586 gint
CDasherControl::KeyPressEvent(GdkEventKey
*event
) {
587 // if((event->keyval == GDK_Shift_L) || (event->keyval == GDK_Shift_R))
588 // SetLongParameter(LP_BOOSTFACTOR, 175);
589 // else if((event->keyval == GDK_Control_L) || (event->keyval == GDK_Control_R))
590 // SetLongParameter(LP_BOOSTFACTOR, 25);
592 // if(m_pKeyboardHelper) {
593 // int iKeyVal(m_pKeyboardHelper->ConvertKeycode(event->keyval));
596 // KeyDown(get_time(), iKeyVal);
602 void CDasherControl::CanvasDestroyEvent() {
605 if(m_pScreen
!= NULL
) {
611 // Tell the logging object that a new user trial is starting.
612 void CDasherControl::UserLogNewTrial()
614 CUserLogBase
* pUserLog
= GetUserLogPtr();
615 if (pUserLog
!= NULL
) {
616 pUserLog
->NewTrial();
620 // "C" style callbacks - these are here just because it's not possible
621 // (or at least not easy) to connect a callback directly to a C++
622 // method, so we pass a pointer to th object in the user_data field
623 // and use a wrapper function. Please do not put any functional code
626 extern "C" void realize_canvas(GtkWidget
*widget
, gpointer user_data
) {
627 static_cast < CDasherControl
* >(user_data
)->RealizeCanvas(widget
);
631 extern "C" gboolean
button_press_event(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
) {
632 return static_cast < CDasherControl
* >(data
)->ButtonPressEvent(event
);
635 extern "C" gint
key_press_event(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
) {
636 return static_cast < CDasherControl
* >(data
)->KeyPressEvent(event
);
639 extern "C" gint
canvas_configure_event(GtkWidget
*widget
, GdkEventConfigure
*event
, gpointer data
) {
640 return static_cast < CDasherControl
* >(data
)->CanvasConfigureEvent();
643 extern "C" void canvas_destroy_event(GtkWidget
*pWidget
, gpointer pUserData
) {
644 static_cast<CDasherControl
*>(pUserData
)->CanvasDestroyEvent();
647 extern "C" gint
key_release_event(GtkWidget
*pWidget
, GdkEventKey
*event
, gpointer pUserData
) {
648 return static_cast<CDasherControl
*>(pUserData
)->KeyReleaseEvent(event
);
651 extern "C" gboolean
canvas_focus_event(GtkWidget
*widget
, GdkEventFocus
*event
, gpointer data
) {
652 return static_cast < CDasherControl
* >(data
)->FocusEvent(widget
, event
);
655 #ifdef HAVE_GTK_CAIRO_SHOULD_DRAW_WINDOW
656 extern "C" gint
canvas_draw_event(GtkWidget
*widget
, cairo_t
*cr
, gpointer data
) {
658 extern "C" gint
canvas_expose_event(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
) {
660 return ((CDasherControl
*)data
)->ExposeEvent();