Porting Windows program

Linux specific forum
harkon
Enthusiast
Enthusiast
Posts: 217
Joined: Wed Nov 23, 2005 5:48 pm

Porting Windows program

Post by harkon »

I am new to PB on Linux so if I come of a bit new, then I appologize.

I am having a great deal of difficulty in figuring out how to create similar GTK calls as to what my windows calls were.

I need to get an set a selection in a string gadget. The lines look like this.

SendMessage_(HandleWindow, #EM_GETSEL, @sStart, @sEnd)
;this gets the start and end positions of the selected text
and
SendMessage_(HandleWindow, #EM_SETSEL, sStart, -1)
;selects text in the string gadget from the start till the end of the string.

I need to emulate this behaviour in Linux. I have DevHelp installed and got some good insight but I can't get a lot of this to work. I must be on the wrong track.

Any help is greatly appreciated.
Missed it by that much!!
HK
User avatar
Shardik
Addict
Addict
Posts: 2067
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Porting Windows program

Post by Shardik »

You should take a look into my list of links to cross-platform code examples. There you will also find links to StringGadget examples which demonstrate how to get and set selected text or how to set the cursor position... :wink:

An alternative when looking for Linux API solutions would be to take a look into Oma's Linux API Libraries...
harkon
Enthusiast
Enthusiast
Posts: 217
Joined: Wed Nov 23, 2005 5:48 pm

Re: Porting Windows program

Post by harkon »

This looks like what I've been looking for.

Thanks for your help.
Missed it by that much!!
HK
harkon
Enthusiast
Enthusiast
Posts: 217
Joined: Wed Nov 23, 2005 5:48 pm

Re: Porting Windows program

Post by harkon »

Currently I use the following routine to get the last keyboard input;

Code: Select all

Structure TagMSG
  hwnd.l
  message.i
  wParam.w
  lParam.l
  time.l
  pt.l
EndStructure

Procedure GetLastKey.w(gadget_ID.l)
Define Result.i
Define LastKey.w
Define MSG.TagMSG

Result=GetMessage_(MSG,HandleWindow,#WM_KEYFIRST,#WM_KEYLAST)
LastKey=MSG\wParam
ProcedureReturn LastKey
EndProcedure

This works well to get the last key pressed. I found code to do this using a callback function but if I use this then I really probably should rewrite the Windows specific part of this to accomodate. There's a lot going on and would rather, if possible of course, just get the last key pressed to make for easier universal code.

The GTK callback code example looks like this;

Code: Select all

;======================================================================
; Module/File:     Keys_GetData.pb
; Function:        Get key and shift - Linux
; Author:          Omi
; Date:            Dec. 18, 2014
; Version:         0.2
; Target Compiler: PureBasic 5.22/5.30
; Target OS:       (X/K)ubuntu ascii/uni, 32/64
; License:         Free, unrestricted, no warranty
;======================================================================

;Shift-States: Bit (depends on installation)
; 0 = [Shift]
; 1 = [CapsLock]
; 2 = [Control]
; 3 = [Alt]
; 4 = [NumLock]
; 5 = 
; 6 = 
; 7 = [AltGr]
; 8 =
;
;26 = [Menue]

#MainWin= 0

ImportC ""
  g_signal_connect(*instance, detailed_signal.p-ascii, *c_handler, *data, destroy= 0, flags= 0) As "g_signal_connect_data"
EndImport


Global.i gEvent

ProcedureC KeyPressCallback(*widget, *event.GdkEventKey, *udata)
	Protected.i I, State, Pressed
	Protected.a KeyAsc
	Protected.l KeyWord
	Protected.s StateKeys, StateNames= "[Shift] [CapsLock] [Control] [Alt] [NumLock] [] [] [AltGr]"
	
	Pressed= *event\type
	KeyAsc = *event\keyval & $FF
	KeyWord= *event\keyval & $FFFF
	State  = *event\state
	For I= 0 To 7
		If (State >> I) & 1
			StateKeys+ StringField(StateNames, I+ 1, " ")
		EndIf
	Next I
	If KeyWord & $8000
		StateKeys+ "[Numberpad]"
		;(1) auch Bit 7 von KeyAsc gesetzt => ausblenden KeyAsc & $7F
	EndIf
	
	Debug #DOUBLEQUOTE$ + PeekS(*event\string) + #DOUBLEQUOTE$ + " = BYTE (ASC): " + Str(KeyAsc) + "/" + Str(KeyAsc & $7F) + ", WORD: " + Str(KeyWord)
	Debug #DOUBLEQUOTE$ + " = BYTE (ASC): " + Str(KeyAsc) + "/" + Str(KeyAsc & $7F) + ", WORD: " + Str(KeyWord)
	Debug "State: " + Str(State) + " = " + StateKeys
	;Debug "Pressed: " + Str(Pressed)
	Debug ""
EndProcedure

If OpenWindow(#MainWin, #PB_Any, #PB_Any, 200, 100, "keyPress to debug")
	g_signal_connect(WindowID(#MainWin), "key_press_event", @KeyPressCallback(), #Null)

	Repeat
		gEvent = WaitWindowEvent()
	
	Until gEvent = #PB_Event_CloseWindow
EndIf
For the life of me I cannot get to where I can find the data structure and method to call in order to make this something I can call on demand.
Missed it by that much!!
HK
User avatar
Shardik
Addict
Addict
Posts: 2067
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Porting Windows program

Post by Shardik »

harkon wrote:For the life of me I cannot get to where I can find the data structure and method to call in order to make this something I can call on demand.
Actually it's very easy: just use a global or shared variable in your callback to store the last key pressed... :wink:

For your conveniance I have put together the following code example which uses a specific callback for Windows and Linux to detect a keypress and store that value in the variable Key. The event loop compares the variable Key (from the callbacks) with a variable LastKey. Whenever they are different, the content of variable LastKey is set to the actual content of variable Key and displayed in the StatusBar:

Code: Select all

EnableExplicit

Define Key.S
Define LastKey.S

OpenWindow(0, 100, 100, 200, 65, "Last key pressed")
StringGadget(0, 10, 10, 180, 25, "")

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    ImportC ""
      g_signal_connect_data(*Instance, SignalName.P-UTF8, *Callback, UserData.I, Destroy = 0, Flags = 0)
    EndImport

    ProcedureC KeyPressCallback(*Widget.GtkWidget, *Event.GdkEventKey, *UserData)
      Shared Key.S

      Select *Event\keyval
        Case #GDK_BackSpace
          Key = "Backspace"
        Case #GDK_Shift_L
          Key = "Left Shift"
        Case #GDK_Shift_R
          Key = "Right Shift"
        Case #GDK_Control_L
          Key = "Left Ctrl"
        Case #GDK_Control_R
          Key = "Right Ctrl"
        Case #GDK_Alt_L
          Key = "Left Alt"
        Case #GDK_Alt_R
          Key = "Right Alt"
        Case #GDK_Return
          Key = "Return"
        Case #GDK_space
          Key = "Space"
        Default
          Key = Chr(*Event\keyval)
      EndSelect
    EndProcedure

    g_signal_connect_data(WindowID(0), "key_press_event", @KeyPressCallback(), 0)
  CompilerCase #PB_OS_Windows
    Define DefaultStringGadgetCallback.I

    Procedure CustomStringGadgetCallback(WindowHandle.I, Msg.I, WParam.I, LParam.I)
      Shared DefaultStringGadgetCallback.I
      Shared Key.S

      If Msg = #WM_KEYUP
        Select WParam
          Case #VK_BACK
            Key = "Backspace"
          Case #VK_SHIFT
            Key = "Shift"
          Case #VK_CONTROL
            Key = "Ctrl"
          Case #VK_MENU
            Key = "Alt"
          Case #VK_SPACE
            Key = "Space"
          Case #VK_RETURN
            Key = "Return"
          Default
            Key = Chr(WParam)
        EndSelect
      EndIf 
      
      ProcedureReturn CallWindowProc_(DefaultStringGadgetCallback, WindowHandle, Msg, WParam, LParam) 
    EndProcedure

    DefaultStringGadgetCallback = SetWindowLongPtr_(GadgetID(0), #GWL_WNDPROC, @CustomStringGadgetCallback())
CompilerEndSelect

CreateStatusBar(0, WindowID(0))
AddStatusBarField(#PB_Ignore)

SetActiveGadget(0)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
  EndSelect

  If LastKey <> Key
    LastKey = Key
    StatusBarText(0, 0, "Last key: " + LastKey, #PB_StatusBar_Center) 
  EndIf
ForEver
harkon
Enthusiast
Enthusiast
Posts: 217
Joined: Wed Nov 23, 2005 5:48 pm

Re: Porting Windows program

Post by harkon »

Thanks for the help. I really was hoping to be able to do this withour a callback function, but I can do the extra work to do this right. The whole thing should probably get a good rewrite anyway.

Once you use the;
g_signal_connect_data(WindowID(0), "key_press_event", @KeyPressCallback(), 0)

How do I 'unconnect'? I will need the same function in different windows and for different string fields. Do I just continue to add connections to gadgets and do they all get destroyed on exit, or do I need to set and unset callback connections? Hope this makes sense.
Missed it by that much!!
HK
User avatar
Shardik
Addict
Addict
Posts: 2067
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Porting Windows program

Post by Shardik »

harkon wrote:Once you use the;
g_signal_connect_data(WindowID(0), "key_press_event", @KeyPressCallback(), 0)

How do I 'unconnect'?
You simply set the callback address to 0:

Code: Select all

g_signal_connect_data(WindowID(0), "key_press_event", 0, 0)
But it isn't necessary to reset the callback. You might as well set the callback to each Gagdet for which you want to capture the pressed keys by replacing WindowID() with GadgetID().

For your conveniance I have again put together a code example which captures and displays each key press of a StringGadget and of an EditorGadget. The new example is again running equally well in Windows and Linux and displays in the StatusBar the last key pressed and the respective Gadget. For the sake of clarity I have removed all the evaluations of modifier keys like <Ctrl> or <Alt> in both callbacks... :wink:

Code: Select all

EnableExplicit

Enumeration 
  #StringGadget
  #EditorGadget
EndEnumeration

Define Key.S
Define LastKey.S

OpenWindow(0, 100, 100, 200, 140, "Last key pressed")
StringGadget(#StringGadget, 10, 10, 180, 25, "")
EditorGadget(#EditorGadget, 10, 45, 180, 60)

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    ImportC ""
      g_signal_connect_data(*Instance, SignalName.P-UTF8, *Callback, UserData.I, Destroy = 0, Flags = 0)
    EndImport

    ProcedureC KeyPressCallback(*Widget.GtkWidget, *Event.GdkEventKey, *UserData)
      Shared Key.S
      Key = Chr(*Event\keyval)
    EndProcedure

    g_signal_connect_data(GadgetID(#StringGadget), "key_press_event", @KeyPressCallback(), 0)
    g_signal_connect_data(GadgetID(#EditorGadget), "key_press_event", @KeyPressCallback(), 0)
  CompilerCase #PB_OS_Windows
    Define DefaultEditorGadgetCallback.I
    Define DefaultStringGadgetCallback.I

    Procedure KeyPressCallback(WindowHandle.I, Msg.I, WParam.I, LParam.I)
      Shared DefaultEditorGadgetCallback.I
      Shared DefaultStringGadgetCallback.I
      Shared Key.S

      Protected DefaultCallback.I

      Key = Chr(WParam)

      Select WindowHandle
        Case GadgetID(#EditorGadget)
          DefaultCallback = DefaultEditorGadgetCallback
        Case GadgetID(#StringGadget)
          DefaultCallback = DefaultStringGadgetCallback
      EndSelect

      ProcedureReturn CallWindowProc_(DefaultCallback, WindowHandle, Msg, WParam, LParam)
    EndProcedure

    DefaultStringGadgetCallback = SetWindowLongPtr_(GadgetID(#StringGadget), #GWL_WNDPROC, @KeyPressCallback())
    DefaultEditorGadgetCallback = SetWindowLongPtr_(GadgetID(#EditorGadget), #GWL_WNDPROC, @KeyPressCallback())
CompilerEndSelect

CreateStatusBar(0, WindowID(0))
AddStatusBarField(#PB_Ignore)

SetActiveGadget(#StringGadget)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
  EndSelect

  If LastKey <> Key
    LastKey = Key
    StatusBarText(0, 0, "Gadget: " + GetActiveGadget() +
      ", Key: " + LastKey, #PB_StatusBar_Center)
  EndIf
ForEver
harkon
Enthusiast
Enthusiast
Posts: 217
Joined: Wed Nov 23, 2005 5:48 pm

Re: Porting Windows program

Post by harkon »

Thank you so very much for your help, it is greatly appreciated. I think I have enough to get going on this. Often learning a new way of doing things, and with the docs on GTK API being quite advanced. these examples make understanding very visual, which is a great way to learn.
Missed it by that much!!
HK
Post Reply